Z
Zod•3mo ago
savage unreal

unnreaal - tsconst schema = z.coerce.string()....

const schema = z.coerce.string().optional();

// type Schema = string | undefined;
type Schema = z.infer<typeof schema>;
const schema = z.coerce.string().optional();

// type Schema = string | undefined;
type Schema = z.infer<typeof schema>;
But z.coerce.string() will always cast the value to a string, why not just string instead of string | undefined?
24 Replies
Scott Trinh
Scott Trinh•3mo ago
Infer is the input type. z.output gives the output type
savage unreal
savage unrealOP•3mo ago
still the same with z.output
Scott Trinh
Scott Trinh•3mo ago
Oh yeah, I guess it would be that type. Optional doesn't make sense here since coerce swallows undefined. 🤔
savage unreal
savage unrealOP•3mo ago
its a type error no?
Scott Trinh
Scott Trinh•3mo ago
Well... sure, I could see that, but really optional and nullable are just not really meaningful for coerce types. Same for union, really Is there something specific you're intending to mean by making it optional? It already accepts undefined as an input.
savage unreal
savage unrealOP•3mo ago
no, i mean that the type (z.output) is wrong
Scott Trinh
Scott Trinh•3mo ago
It's only wrong because .optional makes everything | undefined, but optional doesn't mean anything for z.coerce schemas, so it's "right" but only technically right.
savage unreal
savage unrealOP•3mo ago
yes bro, i know the | undefined doesn't mean anything for z.coerce schemas i mean that the type is completely wrong
Scott Trinh
Scott Trinh•3mo ago
for instance, this is also supported, but doesn't work:
const schema = z.union([z.coerce.string(), z.coerce.number()]);
type Schema = z.output<typeof schema>;
// string | number
const schema = z.union([z.coerce.string(), z.coerce.number()]);
type Schema = z.output<typeof schema>;
// string | number
In actuality, it's always string at runtime.
savage unreal
savage unrealOP•3mo ago
const user = z.object({
name: z.coerce.string().optional(),
});

// { name: string | undefined; }
type User = z.output<user>;
const user = z.object({
name: z.coerce.string().optional(),
});

// { name: string | undefined; }
type User = z.output<user>;
Scott Trinh
Scott Trinh•3mo ago
I mean that .optional should not be an option for coerce schemas.
savage unreal
savage unrealOP•3mo ago
but the name is always a string here so zod should throw an error warning the optional can not (or is unnecessary) be used with coerce schemas
Scott Trinh
Scott Trinh•3mo ago
Nope: this is { name: string; }
Scott Trinh
Scott Trinh•3mo ago
it should just not allow you to .optional() on a coerce schema.
savage unreal
savage unrealOP•3mo ago
nop im sure it isnt it is { name?: string | undefined; } try yourself
Scott Trinh
Scott Trinh•3mo ago
no, your original (without the .optional) is string
savage unreal
savage unrealOP•3mo ago
bro, i edited the message (before you send the playground link)
Scott Trinh
Scott Trinh•3mo ago
yep! don't use optional for coerce schemas.
savage unreal
savage unrealOP•3mo ago
zod should throw an error or at least warn users
Scott Trinh
Scott Trinh•3mo ago
yes it should just not include an .optional method. but it does for now, so just avoid it until we fix that.
savage unreal
savage unrealOP•3mo ago
.optional is in ZodType, no?
Scott Trinh
Scott Trinh•3mo ago
it is! we'll need to fix that. in the meantime, do not: 1. Use optional, nullish, or nullable with z.coerce schemas 2. Use z.coerce schemas in a z.union 3. Probably other stuff.
Scott Trinh
Scott Trinh•3mo ago
GitHub
We should not allow optional, nullish, or nullable on `z.coer...
Since z.coerce.* schemas will always return the primitive, even if you pass undefined or null, we should disallow this. Also, things like z.union([z.coerce.string(), z.coerce.number()]) will always...

Did you find this page helpful?