Z
Zod•2mo ago
neurotech

neurotech - Hi everyone. I'm struggling with zo...

Hi everyone. I'm struggling with zod 4 and how it handles coercing values. This is my scenario: I have a form that contains a "Port" input that has a type of number. AFAICT, the typing of this input's value is a string, so I need zod to coerce it to number in order to validate properly against this schema:
export const ConnectionFormSchema = z.object({
host: z.string().nonempty({
error: "Must not be empty.",
}),
port: z.coerce
.number()
.min(MINIMUM_PORT, {
error: PORT_VALIDATION_MESSAGE,
})
.max(MAXIMUM_PORT, {
error: PORT_VALIDATION_MESSAGE,
}),
authenticationToken: z.string().optional(),
});
export const ConnectionFormSchema = z.object({
host: z.string().nonempty({
error: "Must not be empty.",
}),
port: z.coerce
.number()
.min(MINIMUM_PORT, {
error: PORT_VALIDATION_MESSAGE,
})
.max(MAXIMUM_PORT, {
error: PORT_VALIDATION_MESSAGE,
}),
authenticationToken: z.string().optional(),
});
In my form, I have a call to form.watch:
const [host, port, authenticationToken] = form.watch(["host", "port","authenticationToken",]);
const [host, port, authenticationToken] = form.watch(["host", "port","authenticationToken",]);
I use these values in a separate component, and this is where I'm struggling. The type of port returned from form.watch is unknown, even though I'm coercing it to a number. Am I going about this the wrong way, or is there something I'm missing?
Solution:
Thanks @janglad - I ended up doing this:
z.coerce.number<number>()
z.coerce.number<number>()
...
Jump to solution
9 Replies
janglad
janglad•2mo ago
Passing those generics shouldn't be needed anymore but inference for the zodResolver doesn't seem to be working on tsplayground but the issue here is that z.coerce results in a type with unknown as input and watch gives you unparsed/non transformed values which in this case would be of type unknown Part of the reason why I'm personally not huge on coerce. You could make use of zod's new codecs if you're on the latest version
Solution
neurotech
neurotech•2mo ago
Thanks @janglad - I ended up doing this:
z.coerce.number<number>()
z.coerce.number<number>()
neurotech
neurotechOP•2mo ago
I can bump to the latest and look into codecs though
janglad
janglad•2mo ago
well by doing that you now have a schema that (at least on the type level) takes in a number and returns a number right Have a look at the result you get from watch, it should be a string
neurotech
neurotechOP•2mo ago
The type of port from form.watch is number 😮
janglad
janglad•2mo ago
At runtime? I’d swear watch gives non transformed values haha But might be wrong
neurotech
neurotechOP•2mo ago
not sure at runtime, but the type in my intellisense is number
janglad
janglad•2mo ago
Aah right, yeah that makes sense 🙂 Since the input type is also number

Did you find this page helpful?