Is there a way to set a default value that is not valid?
This is due to svelte 5 - where you have to provide a meaningful non-undefined prop for bound values. e.g. for radio buttons, you need to default to
""
, not undefined.
I am not sure how to define an Arktype type that accepts only an enum of values from the radio button, but defaults to empty-string. When I do the obvious inputType.default("")
I get errors:
ParseError: Default value is not assignable: must be "enum_option" (was "")
104 Replies
I would just cast your value
oh, I mean this is a runtime error
it breaks at type instantiation time
Ahh
Hmm
Well instead of using a default value, you could morph the base object to add it if it's not there
this is potentially more broadly useful to default a form control to an invalid (but meaningful) value for the user to modify
Yeah that's much more relevant than if it were a type issue
I would consider some syntax to bypass default value checking
Would you want to create a GitHub issue?
sure, I will do that after this meeting, thank you!
Sometimes all the runtime safety can be too smart for it's own good 😛
Something like this is what I meant for the morph workaround, not sure if that is exactly what you're looking for beyond the syntax obviously being less elegant:
What do you think about making two different validators?
Or an context-aware validator
I ended up fixing this elsewhere, but I needed to use the same validator for defaults and for real validation
I didn't end up making an issue since I'm not entirely sure the use case for this anymore
How did you solve this?
I didn't. superforms + arktype is incompatible currently so I gave up on using it for now
but I also fixed it on the client side since the issue was transforming a form default undefined value to a non-undefined value for binding to a child prop in svelte 5 (which can no longer be undefined from the parent)
@ciscoheat has an ArkType resolver in
sveltekit-superforms
so there must be some potential for compatibility, no?
If there are fundamental incompatibilities would be good to understand them so I think about how an adapter might work.ah no it was just a breaking change in internals I t hink
GitHub
Appears to no longer be compatible with arktype as of `[email protected]....
const testObj = type({ foo: "'foo'" }); superValidate({ foo: null }, arktype(testObj, { defaults: { foo: "foo" } })); This now triggers: file://project/node_modules/@ark...
Yes, I can confirm that this breaks the tests. I'll do some investigation
Seems like error.path is now a
ReadOnlyPath
Any way to extract the path as an array, as it was before?. slice()?
Or is it a string?
It's an object
@ark/util/out/path.js:33
It says it extends ReadonlyArray<PropertyKey>
So it's an array
So .slice() it to clone to PropertyKey[]
Yes, but also an object since it got some extra methods, but I'll try
Got the same error when trying slice
Solved it with
Array.from(error.path)
Oh hmm this sucks. Having the array subclass is more of a convenience for path serialization- I wasn't expecting it to be a breaking change.
So this was a runtime issue where using
TraversalPath
ends up not being spreadable?Yes
ReadonlyArray
is just Array
at runtime
So it's an array subclass but it shouldn't actually be different in terms of what you can do with it so maybe I forgot to bind something somewhere or it's one of those array subclass pitfalls I didn't know aboutYeah, arrays are messy in that way
But I managed to fix it so it works with Array.from
Definitely appreciate you found that but I do want to make sure that doesn't happen to anyone else. It seems like it was my fault
Would it work with .slice could you check
It didn't work with slice
He said no I think ahha
But even so
TraversalPath
is really only worthwhile if you can use it just like an array
I think that's been true of ArkErrors
Weird
Do you happen to have a minimal-ish repro of the non-iterable issue
^this please
Oh no I totally get it now
Yeah I'm dumb
I mean I do blame JS here also because array constructor is a terrible API haha
But my solution is not a solution
I actually wrote this when working on
TraversalPath
The
Array
constructor defies all logicLike yeah there are other janky things about JS but this feels so obviously wrong from a language/ API design perspective
Hmm so what do I actually do here
I don't even know how to work around this
I guess I need to accept
...
args and just treat a single number as an array of one instead of doing the nonsense JS doesWhat was the problem with the (real) array in the first place?
There wasn't a problem really there were a lot of places in the code base where I wanted to do special stuff related to serialization and comparison of paths so I thought it would make my life easier to create an array subclass that let you do it directly, but seems like I was wrong
Ok, yeah, I guess it's a bit of a problem if the error path doesn't behave just like an array
It definitely needs to behave just like an array or it's not a good abstraction
Yes
But AFAIK I've had succes with ArkErrors being an array subclass with extra functionality and not causing problems
So maybe it's just that I screwed up the constructor
Maybe you can use that internally, and call Array.from when you're about to return the errors?
If you need the extra features of the subclass
I think I will try to get it to behave consistently if I can't do that I'm just going to remove it
I'm sure you'll figure something out. 🙂
Yeah I mean worst case scenario I just convert it back to some helper functions I need to remember to call
It's really weird that using
.freeze
on an array breaks stuff like .map
and .slice
Yes, I didn't know that
I can't really even figure out how that is possible
I guess if the new array is already frozen when it is mapped? I don't see why it would be
Maybe because the prototype of freeze is on Object
And arrays are "objects"
Yeah but I still don't see what would be mutated there
Like when I tried to do this:
I get:
Cannot redefine property: 0
Tf
Looks like a bug
What if you freeze a regular array?
And the snapshot logic that breaks:
It just breaks on
.map
. Yeah arrays are kinda like objects under the hood but the question is why is 0
being written toObject.freeze([1]).slice()
?
That works
Huh
Subclassing in typescript compiles to something messy?
?
It seems like it breaks if you freeze in the constructor
I don't see why that is semantically different from what you wrote though
Huh
What if you void this.length?
Before freesing
Idk exactly what you mean but if I add
void this.length
it doesn't do anythingI'm stumped
I'm going to post it and see if anyone knows haha
Hmmm
Gotta take some rest now, nice chatting
I do have an idea though
@ssalbdivad does class extends array .slice() produces an instance of the same class?
Yes
I guess thats where it breaks idk why
What is where it breaks
Probably because it writes to it after its constructed
Try setting its species to Array
Yk whats species?
No idea
How does that make sense though
MDN Web Docs
Array[Symbol.species] - JavaScript | MDN
The Array[Symbol.species] static accessor property returns the constructor used to construct return values from array methods.
Shouldn't it be written to in the constructor
If the constructor accepts
...items
No
.map acts exactly like a polyfill
Map is like:
1. init []
2. push items?
sorta
Probably assings rather then pushes tho
Hmmmm
@ssalbdivad so could you try Path[Symbol.species] =Array?
But I would want it to still be the same class
Hmmm
Why?
Because to me that is intuitively how map should work
It does fix the issue though
I mean that makes sense
Based on what you are saying, because it doesn't run the subclass constructor
\o/ we found a fix
Not the fix tho
Because it writes after constructor
The way that makes sense to me to create a plain Array from a subclass would be
Array.from(subinstance)
or [...subinstance]
That is so ridiculously unintuitiveTry making a polyfill that doesn't do that
I mean because of Array's terrible constructor API I guesss?
So this all ties back to that?
Idk ¯\_(ツ)_/¯
Okay I guess I kind of see it
You need to construct an array to have something like
...args
to passYou can't implement a .map that doesn't write into array without using a second array
Yeh that's second array
Es6 feature
Array.prototype.map works even on objects lol
Try Array.prototype.push into an object lol
Well it may be not optimized but it does work
Yeah that's what I mean
So they wanted it to be possible to polyfill so they end up with this very weird logic
I mean still very unintuitive but more reasonable once you think about it than the constructor API itself
It may have less sense now but it probably did 25 year ago when it was made
There's no way that was ever a good decision
If it would be made now it would always make an Array instance like toSorted does
Doesn't matter which overload came first or if both at the same time- adding overlapping signatures was a big mistake
Wym
Ah
Well maybe
To be fair it's one of the few times where I've felt like something in JS is egregiously bad and relatively easy to run into if you avoid
==
and know typeof null === "object"
Most complaints are pretty contrivedIt was probably made in that first 10 days js was made in
Do you think they added both right away or added the ..args later?
... Is es6
Okay but you could still do the same thing with
arguments
What thing
Accept n items in the constructor
IDK it kind of feels like it would be cyclic though I don't know what the internal logic looks like there. I guess that has to be native code
@ciscoheat Well I definitely am not at all invested in the array actually being frozen at runtime so I'm just going to remove that.
In the next release, array methods should work fine with
TraversalPath
, so at that point feel free to switch back to the previous implementation. Or not, what's there now should be fine too 👍