Does coerce defeat the purpose of infering a type from a schema? #3805
Replies: 2 comments 1 reply
-
A follow up thought: It feels like a better way to design the The syntax should look something like: z.string().coerce(z.number().min(0).max(1)), Thus you would be explicit about what the value actually is (a string) and what you're validating it as (a number). Because right now, when used in the manner described above with |
Beta Was this translation helpful? Give feedback.
-
Can you explain further why you need Another option would be to use const schema = z.object({
winner: z.string().transform((value, ctx) => {
const valueAsNumber = Number(value);
if (isNaN(valueAsNumber)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Winner should be a string representation of a number.",
});
return z.NEVER;
}
return valueAsNumber;
}),
});
type InputType = z.input<typeof schema>; // { winner: string }
type OutputType = z.output<typeof schema>; // { winner: number } If needed, you can do additional min/max checks within the transform. |
Beta Was this translation helpful? Give feedback.
-
Background
I'm working on a React project where I have a form with a schema which looks something like:
Logically, I chose to implement it this way so that if one of the players is changed (or swapped), the winner ID doesn't become out of sync.
However, I'd like to allow the user to select the winner from a dropdown of the two players. Thus logically I'd have something like:
...only most Select components I've found (in my case I'm using Radix UI) don't support non-string values because HTML selects don't support non-string values.
So I can solve this by using
"0"
and"1"
as my values, and adapting my schema withcoerce
:winner: z.coerce.number().min(0).max(1)
.But here's the problem...
If I infer the type from my schema, Typescript will say
winner
is a number, because that's what Zod says it is. But if I try to checktypeof winner
, it's a string.Of course, for the sake of using Zod to validate my form inputs, I want it to coerce the string into a number, but when I infer the type from the schema I want it to accurately reflect the fact that
winner
is astring
. This seems to go against the idea that Zod is TS friendly if the type I've inferred from the schema is actually wrong.Of course, the really ideal situation would be that
winner
is anumber
andz.coerce
is not needed at all, but that's a question for Radix. It doesn't change the fact that I'm curious, "Why does this method (z.coerce
) exist which seems to create wrong typings by design?"So the big questions are...
winner
could be az.string()
since that's what the form input uses, but then I can't use number-specific validation tools like.max()
and.min()
.Beta Was this translation helpful? Give feedback.
All reactions