I have a following zod example:
const objectSchema = z.object({
optional: z.string().optional(),
other: z.string(),
});
// the current default behavior:
objectSchema({ other: "other" }) //pass.
objectSchema({ optional: undefined, other: "other" }) // pass
objectSchema({ optional: "str", other: "other" }) // pass
In typescript, optional field key?: string
will be converted to key?: string | undefined
. But it's strictly different during the runtime check.
The previous one during the runtime check could be interpreted as the optional
must be string
if it exists, hence optional: undefined
is an invalid input.
So, is there any way I can do with zod that makes the undefined
an invalid input.
hence
objectSchema({ other: "other" }) //pass.
objectSchema({ optional: undefined, other: "other" }) // fail
objectSchema({ optional: "str", other: "other" }) // pass
That's my current attempt, which is fine if there is only one optional field, but it starts to become extremely messy and unusable (z.object().or().or().or()), basically (the number of optional field)^2 permutation
.
const objectSchema = z.object({
optional: z.string(),
other: z.string(),
}).strict().or(z.object({
other: z.string(),
}).strict());
Based the answer from the zod
discord community/github collaborator.
zod
is strictly following the current typescript
behavior.
Typescript cannot distinguish the runtime difference between
// key is either missing or key exists with type string, cannot be `undefined`
type object {
key?: string;
}
and (in fact the first one will be converted to the second one)
// key may or may not exist with the type string or undefined.
type object {
key?: string | undefined;
}
Hence, if you want to strictly enforce the first behavior in runtime, you need to explicitly remove undefined key by yourself. There is no such a shortcut from zod
.
if (key in object && typeof obj.key === "undefined") {
delete obj.key
}