Value or undefined is not the same as an optional, and should not be a required property either #971
Replies: 12 comments
-
I guess I'm not really seeing what problem you are talking about. I tested 2 situations and they both seem to be working as expected. Please help me to understand what is not working correctly. type A = {
b: string | undefined
}
const a: z.ZodSchema<A> = z.object( {
// ^
// Property 'b' is optional in type '{ b?: string | undefined; }' but required in type 'A'.
b: z.string().optional(),
} )
type inferredA = z.infer<typeof a>
// type inferredA = {
// b: string | undefined;
// } const foo: z.infer<z.ZodSchema<{ b?: string | undefined }>> = {} // no error
const bar: z.infer<z.ZodSchema<{ b: string | undefined }>> = {} // error
// ^^^
// Property 'b' is missing in type '{}' but required in type '{ b: string | undefined; }'. |
Beta Was this translation helpful? Give feedback.
-
@JacobWeisenburger type A = {
b: string | undefined
}
const a: z.ZodSchema<A> = z.object({
b: z.union([z.string(), z.undefined()])
})
// ^^ also throws: Property 'b' is optional in type '{ b?: string | undefined; }' but required in type 'A'.ts(2322)
// (same with z.string().or(z.undefined())) So, question I still have is, how do I write the union of const a: z.ZodSchema<A> = z.object({
b: ????
}) |
Beta Was this translation helpful? Give feedback.
-
It seems that somewhere in z.object(), anything that type A = {
b: string | null
c: string | null
d: string | null
}
// You could define your zod schema any of the 3 ways below.
const a: z.ZodSchema<A> = z.object( {
b: z.union( [ z.string(), z.null() ] ),
c: z.string().or( z.null() ),
d: z.string().nullable(),
} ) https://stackoverflow.com/questions/5076944/what-is-the-difference-between-null-and-undefined-in-javascript |
Beta Was this translation helpful? Give feedback.
-
@JacobWeisenburger Anyway, I would consider it a bug with zod if it's impossible to write the union of e.g. |
Beta Was this translation helpful? Give feedback.
-
Ok fair enough. I'll change it back |
Beta Was this translation helpful? Give feedback.
-
Just ran into this and consider it unexpected behavior myself. An example with an explicit transform: property: z.string().transform((v) => v || undefined)
// { property?: string | undefined } A workaround is to transform the containing object: z.object({
property: z.string(),
})
.transform((obj) => ({ ...obj, property: obj.property || undefined }));
// { property: string | undefined } |
Beta Was this translation helpful? Give feedback.
-
Would love to have a solution like this. I have a lot of scenarios where I want to force the caller to pass It would be amazing to have |
Beta Was this translation helpful? Give feedback.
-
I, too, would love a solution for this. In like @bluepnume and @emanuel-lundman said trying to verify something with explicitly set undefined and with optional keys are very different things. type User{
name: string;
email: string | undefined
} is completely different than type User {
name: string;
email?: string
} In our codebase we are still using |
Beta Was this translation helpful? Give feedback.
-
Run into the same issue, |
Beta Was this translation helpful? Give feedback.
-
just weighing in to say that i also would not expect unioning with undefined to automatically make the field optional. typescript already explicitly differentiates between |
Beta Was this translation helpful? Give feedback.
-
+1 Object spreads are a common place where the difference matters:
I often rely on omitted keys to spread in default values. Zod could make this simpler by offering a schema that can coerce null or undefined to an omitted key. |
Beta Was this translation helpful? Give feedback.
-
Just to link the issue to this discussion; #3186 |
Beta Was this translation helpful? Give feedback.
-
is not the same as:
The first requires undefined to be set, and can't just be left out.
Zod though both seem to infer:
to an optional when writing the schema first and then inferring a type. And when doing the other way around, writing a schema for the type, thinks it's required and only accepts the following:
even though it should be
z.string().or(z.undefined())
But writing is it should be results in error:
Property 'b' is optional in type '{ b?: string | undefined; }' but required in type 'A'
Am I missing something?
Beta Was this translation helpful? Give feedback.
All reactions