Automatically applying parse.integer
Let's say I have a type I'm using to validate some API, e.g.
At some point, I also want to use this type to validate form input. As it's formData,the age will be a string not a number.
I know I can do something like this:
However, is there a way to somehow automate the coerce step? I have lots of these types (some of them dynamically created) and I'd rather avoid having to manually create an extra type to pick out the numeric fields and parse.integer them.
Maybe there's some way I can automatically pick out the number properties from a type and automatically build the coerce step so that parse.integer is only applied to any properties that are numeric in the final schema?
I'm fairly new to this, so it could just be my lack of Typescript skill. Any pointers would be much appreciated.
108 Replies
Sounds doable but definitely a bit tricky. There's no built-in "coerce" yet. I'd have to think about what the semantics of that would be relative to the existing parse keywords.
Where does personSchema come from? Could that be defined in a way where the parsing happens there, and the output could be extracted separately?
If you already have the personSchema type to compare with the form input, I guess you could iterate over the keys that way to see which should be converted to numbers
I'd assumed 'parse.integer' would convert a string to an integer and leave an integer alone, but if fails if the input is already an integer. Would there be a problem with having parse.integer just pass through the existing value if it's already an integer?
The personSchema is just a simple example. I have a whole bunch of data objects that can be written to a db, both via an API (where numerics will already be numbers) and forms (where the numerics will be strings).
I've built a simple form validator, to which I pass the formData and the arktype type. The validator function uses the passed type to validate the input and passes back the original data and a success message or errors.
I can always deal with this by creating 2 types instead of 1. One is the "API" type and the other one is a parse.integer for the numeric fields and piped to the API type. It just felt a little redundant. Feels like there should be a more elegant way.
I can always deal with this by creating 2 types instead of 1. One is the "API" type and the other one is a parse.integer for the numeric fields and piped to the API type. It just felt a little redundant. Feels like there should be a more elegant way.
I don't think I would ever make morphs accept their output types in general just because it's sometimes convenient
But I might add some additional keywords to help with that
e.g. there is a lift array that converts something to an array if it is not one already so it would be somewhat similar to that
I'm sure the right abstractions could help but it's important to strike a balance and not start implementing magical transformations with lots of edge cases as built ins. Ideally they should primarily be simple I/O
I think if I were going to add something like this though it would probably be like
number.integer.coerced
Thanks David.
In the meantime, if I already have a type() defined, is there any way I can extract the keys of numeric properties from that type? I could then use them to build my parse.integer step.
A bit tricky to do, especially if you don't know the runtime type system but this seems to wrok
Thanks! And having read that, there's also the added bonus that I no longer feel dumb for not knowing how to do it myself 🤣
Yeah like I said definitely not the most trivial thing either at a type-level or at runtime haha
I have the same use case
I would like to achieve such behavior
Can't you just write a morph?
Ooooh, you updated docs!
I added a few new sections. I also have some good abstractions for showing multiple definition types
Oh righttttttt.... So this forum is about doing it inherently
Sorry 🙈
Yeah, youc ould always just write
number.integer|string.parse.integer
Which I think is a lot clearer anywaysYou could?????
Why not?
I never saw the
parse.*
being used in this way, it never even came across my mind
Just assumed it wouldn't workOh I guess I wrote it wrong haa
It should have been
string.integer.parse
Because it seems so complicated to implement
What part? It's all just composable rules in the type system
Hehe...
The DX is just too good to be true
I love it
A conform adapter would actually be really useful I know a couple teams that use conform that are interested in ArkType
I am in the process of making one
So I see, really excited to see that! Happy to do a review once it's ready
It works with the strings, now just to add morphs
I'm thinking whether creating an exported
scope
would be the best way...
The scope would then be extended and have all the necessary keysDefinitely an option. Most things you can do with or without a scope so it comes down to preference.
Scopes let you use the string syntax more with your own keywords and there's a couple things they let you do that would otherwise not be possible:
- Configuring sets of types at once
- Representing cyclic types
Outside that though it is down to preference really
Because with Zod it's kind of simple to override the behaviour. Because it's not composable in the same way, the library authors can simply predict what the users might want
But Arktype allows for many crazy things to happen
You can just accept an option for
preprocess
or whatever Zod does right?Is it possible to create bookmarks on Discord? 😩
Then make that the initial morph, and pipe it to whatever the validated types are
Haha I don't think so.... I'll include all this in th edocs soon though:P
Yay
I'll bookmark that
Right should be very convenient since the docs will be your home page anyways 😛
If it'll have a theme toggle, I'd put it on the desktop
Haha it used to but I don't have ArkLight so I got rid of it 😛
So the same theme that would be used in VS code would go to the website?
Yeah it literally imports ArkDark from the dir that publishes it
I'd need to map the colors as you explained right?
Yeah I would accept a PR for sure on that though
If you added a parallel ArkLight theme + updated the css for the docs to include a light-mode palette
I don't know how to do those :/ Never commited to a private repo
It's not a private repo
Got it
public, public!
Oh haha
GitHub
arktype/.github/CONTRIBUTING.md at b52212ea0874064a325c1e212a286d2a...
TypeScript's 1:1 validator, optimized from editor to runtime - arktypeio/arktype
PRs, FR etc, no idea
It's a little out of date possibly in some places but it is pretty straight forward
:ooooo
Alright, no excuses ;)
It could be a bit tricky to get the styling customizations right for the code blocks, just try to use as many css variables as you can I guess
To easily swap between palettes
It's funny, because it already supports my
@ark/i18n
thing 🙈Also when you're editing ArkLight, by far the easiest way to test changes is going to Run and Debug in VSCode and clicking
ArkDark Dev
It will launch a new VSCode window that reflects your changes
Peeeeerfect
Yes, I'll mirror the dark theme
Could be great!
ArkLight is a nice name too
Kinda flows off the tongue
But ArkDark rhymes 😁
Yeah I mean it's not as good as that
But ArkLight sounds like ArkWright I guess?
Definitely, I'm a heavy light theme user
I don't know when that happened, probably when I started coding outdoors
You're ArkRight
One of a small number of words that starts with Ark haha
Oh my
ArkWright will be the tool that generates ArkType schemas compatible with every programming language
Or the tool that controls Playwright instances only using the composable type definitions, I'm still on the fence
The really funny thing is the initial motivation for working on ArkType was actually a UI testing framework I was building on top of playwright so not far off
This is how they do it in
@conform/zod
:
I guess the change will be _def
to expression
, like I did in shady-ark-i18n
What are you looking to check, if the schema is a number?
If the individual key was set up as a number
Age should be piped to
number
when an HTML field passes the stringified numberOh, and it returns a boolean?
Yeah
Wow...
I'm really complicating things in my head, aren't I
This does seem a lot like the original question though
Yeah...
I would just do this then:
This won't be enough, since there are other simple conditions
But you can use the same patterns to transform the schemas
Yes
Seeing such code is so cool 😁 Peak TS
Hah well ideally this kind of stuff is externally simple. I would definitely consider building in some abstraction for common form transformations
Okay, I got it! Such patterns for each condition
And in the end
merge
Actually I'd just write it as one mapping like that
So you don't have to use merge
Basically just iterate over each key the way I am there, but then directly create a new object with the updated types
Would be a great use case for mapped types once those are implemented
Ooooohhhhhhh
Right, this was for filtering
That's why it had the
null
Sorry, it's been a loooong day 😁Yeah in reality you'd check for the conditions then if it doesn't mean any of them just keep the value the way it is
Yeah this is perfect
No problem not your fault. It would be good to have builtins to make this easier
Should this type return actual types or strings?
o
is t
You don't want to pass a type instance
Well
Type["t"]
is nothing so you can just remove that constraintI'm happy about that 😁
k
is the key getArkKey<o, k>
is the valueThis type seems almost redundant?
It's for filtering the keys
Since we're not filtering anymore
Just an easy way to distrubte over them
Yes
Yeah you'd probably want an actual mapped type
So no index access at the end
But since the result in the runtime will be what we put in the type
Then there's no much reason to map over the type itself
There might be because you will have to cast the mapped type potentially? I guess it depends if you need the exact types for this
Almost like this would be enough?
Oh no 😩
Updated to the latest version
string.url
?Seems to also be missing
I really like how it's under
string.*
now
Will make everything more organized for sureHmm really
I'll just put in
string
for nowstring.url
will work at runtime I just missed including the type
It will be back in the next releasePerfeeect
I need the d.ts build in this particular package, because I couldn't figure any other way to share its Arktype definitions otherwise 😁 And one dts build takes 15-20 seconds, not sure why
Hmm that sounds a bit sketchy but ok haha
I'm happy it at least works. I update that package rarely anyways
What is the proper way to ge the whole type in the end?
You may make yourself a server and copy message link like https://discord.com/channels/957797212103016458/1276473191421837382/1281024651937714258
Oooh, neat, thanks!
@PIat
string.url
back in 2.0.0-rc.6
!Yay, thanks!
Did you every get this working?