z.coerce.string()
casts undefined
to "undefined" string
#2804
-
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, |
Beta Was this translation helpful? Give feedback.
Replies: 7 comments
-
This is the expected behaviour, as It's recommended to initialize your form with 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)) |
Beta Was this translation helpful? Give feedback.
-
I believe this is a bug. It's not obvious that this transformation may disable the
|
Beta Was this translation helpful? Give feedback.
-
Well, it's definitely not a bug. As you can see in the doc, z.coerce.string(); // String(input) So of course |
Beta Was this translation helpful? Give feedback.
-
Then it can be improved. Usage of It's also possible to solve this issue from the other side - make the Related: #2461 |
Beta Was this translation helpful? Give feedback.
-
Well, I'd suggest using E.g. It's kind of a trade-off. If you choose |
Beta Was this translation helpful? Give feedback.
-
In my opinion, this is surprising behavior, but it also interacts in surprising ways with const foo = undefined;
z.coerce.string().parse(foo);
// 'undefined'
z.coerce.string().optional().parse(foo);
// undefined
z.object({
foo: z.coerce.string(),
}).parse({});
// { foo: 'undefined' }
z.object({
foo: z.coerce.string().optional(),
}).parse({});
// {}
z.object({
foo: z.coerce.string(),
}).parse({ foo });
// { foo: 'undefined' }
z.object({
foo: z.coerce.string().optional(),
}).parse({ foo });
// { foo: undefined } |
Beta Was this translation helpful? Give feedback.
-
In my case I just wanted to convert primitive types like number/boolean to string due to third-party content. I forgot about this working on undefined... So now I use a custom helper so it will fail if it's unexpected: export function safeCoerceToString(initialValidation: z.ZodString) {
return z.preprocess((value) => {
if (typeof value === 'number' || typeof value === 'boolean') {
return value.toString();
} else {
return value;
}
}, initialValidation);
}
// Possible usage
safeCoerceToString(z.string().min(1)).parse(12); |
Beta Was this translation helpful? Give feedback.
This is the expected behaviour, as
corece
under the hood runsString(input)
.It's recommended to initialize your form with
''
or write your own transform logic, e.g.Or you can implement your own preprocessor