Runtime coercion
I'm building a system to load declarative runtime configuration from a couple different sources, all of which provide values as strings (env vars, AWS SSM Parameters).
Currently I'm walking through the 
typeJson at runtime to build accessors for each field, such as joining field names with __ to build environment variable keys, and that is working great. I can cleanly detect when I reach a "leaf" type to load, and I either have a string or an object with a "domain"; my challenge is whether there is an elegant way of coercing the string I load into the type expected at this point (without making some huge imperative logic block).
I'm hopeful there might be some clever thing under the hood that I can use in place of rolling my own.
Also, are there types defined somewhere that more concretely describe the typeJson structure?29 Replies
Hey,  cool to hear you've been delving into some of the type system in depth!
The easiest thing would be to traverse the type nodes directly instead of the JSON.
If you create a type like:
I'm not totally sure what you mean about coercing the string into an expected type, maybe an example would help?
Sure! (also, thanks for the quick reply!)
So, I want to define a "config" type like 
and then introspect that type to load the value from 
process.env.SERVER__BASE_URL.
This works fine currently if the type (url in this case) is a string-based type, but if I want to load a number, I need a way to coerce into the base type (before any validators)Maybe something like this would be helpful:
It's not like Zod where there's a "before validation" phase or similar, types can be chained through transformations to other types
There are also some builtin keywords that could be helpful here like 
parse.numberOh that sounds interesting
where can I get 
parse.number?It should be available by default
As a global?
Like  I mean
You can also import 
ark
And use ark.parse.numberOh I see
still wrapping my head around using 
type like thatThe completions should help a lot
yeah, those are super nifty
And very specific error messages if you get anything wrong
kudos on building such an intricate type machine
The best thing about the syntax IMO is that once you call type once you don't have to keep wrapping things
You can define an object as deep as you want within a single type call
how would I go about parsing a comma separated string into an array of things
So it looks much more like pure TS syntax
Then whatever additional transforms/validation you want on each item
I'm guessing thats what I would use a morph for?
Yeah
Pipe accepts N morphs. Where another 
Type is basically just a morph that will stop chaining if there are errors if you need intermediate validation🤯
I hope once people get the hang of the first few concepts everything is very composable and intuitive from there.
Working on new docs now 🙏
Should this work as an inline morph: 
Which version are you using?
2.0.0-dev.18 I believeAhh okay that was the alpha morph operator for inlining, you want 
=> in 2.0ahh, that makes more sense too
You shouldn't need to explicitly type 
string although there are limits to what TS will do with some nested tuples
You  can also always define the morph type on its own, then reference itI think it was just lacking inferrence because of the wrong operator in the middle
yep, works without the explicit 
string
Or you can inline the type call, whatever is easiest (although I've found defining them as separate variables is nice for reusability, readability, and TS has an easier time with it)
Or tuple expressions, it's really just the nested type` calls that TS doesn't likeOne last question for you @ssalbdivad (though I see you're offline for now, so no rush)
If I wanted to do 
listOfInts how should I go about adding validation? Just doing 
allows for NaN to slip into the array
I tried type('string').pipe((s) => s.split(',').map((x) => type('integer')(x.trim())));  but that felt clunkyMaybe this?