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?????