`z.coerce.string()` casts `undefined` to "undefined" string
andrew-sol opened this issue · 7 comments
Here are the rules:
{
title: z.coerce.string(),
}
As you can see, the field "title" is required. But in case you don't pass it at all, coerce
fills it with "undefined" and the validation passes. And later this "undefined" gets passed into the rest of the app's logic.
This is the expected behaviour, as corece
under the hood runs String(input)
.
It's recommended to initialize your form with ''
or write your own transform logic, e.g.
title: z.any()
.transform(val => val == null ? '' : val.toString())
.pipe(z.string().min(1))
Or you can implement your own preprocessor
title: z.preprocess(val => val == null ? '' : val.toString(), z.string().min(1))
I believe this is a bug. It's not obvious that this transformation may disable the required
rule.
coerce.string()
should cast null
and undefined
to an empty string.
Well, it's definitely not a bug. As you can see in the doc, coerce
is just syntactic sugar to transform with Primitive Constructors.
https://zod.dev/?id=coercion-for-primitives
z.coerce.string(); // String(input)
So of course undefined
will be evaluated into 'undefined'
, it's just how JavaScript works
Then it can be improved. Usage of coerce
in its current form makes no sense unless you wanna shoot yourself in the leg (I use it on backend).
It's also possible to solve this issue from the other side - make the required
rule run before the coercion, but it will be much harder to achieve.
Related: #2461
Well, I'd suggest using yup
then if you want to work with form validation smoothly. zod
is designed to mirror TypeScript
at runtime, hence a lot of behaviours are weird when it comes to validating forms, where yup
is designed for validating forms.
E.g. z.string().min(1)
vs yup.string().required()
is something you have to do if you want to reject empty string using zod
. It doesn't make sense to me either, but you are forced to do so.
It's kind of a trade-off. If you choose zod
, then you get the maximum type-safety but you somehow need to workaround a lot of uncomfortable scenarios when validating forms, but with yup
you can almost write any kind of form validation smoothly, but the types are not guaranteed to be correct or even missing sometimes.