resolvers
resolvers copied to clipboard
issue: [Zod v4] Typescript error when using zodResolver with z.coerce
Version Number
5.1.1
Codesandbox/Expo snack
https://codesandbox.io/p/sandbox/dark-cookies-5xmdf4
Steps to reproduce
- Define a schema that has
z.coerce - Use
useFormwith the generic type parameter that is returned byz.infer - Register resolver through
zodResolver - Observe error in the resolver
Expected behaviour
It shouldn't show the Typescript error.
There were 2 closed issues related to this #751 and #743
It seems there is a input type mismatch in the conversion as the zod v4 introduce a change to the input type when using coerce
What browsers are you seeing the problem on?
Chrome
Relevant log output
Type 'Resolver<{ height?: unknown; weight?: unknown; }, any, { height?: number | undefined; weight?: number | undefined; }>' is not assignable to type 'Resolver<{ height?: number | undefined; weight?: number | undefined; }, any, { height?: number | undefined; weight?: number | undefined; }>'.
Types of parameters 'options' and 'options' are incompatible.
Type 'ResolverOptions<{ height?: number | undefined; weight?: number | undefined; }>' is not assignable to type 'ResolverOptions<{ height?: unknown; weight?: unknown; }>'.
Type 'unknown' is not assignable to type 'number | undefined'.ts(2322)
Code of Conduct
- [x] I agree to follow this project's Code of Conduct
Short answer: don't pass an explicit generic to useForm<> anymore. The schema types are all inferred now. Unfortunately the code example from the website (useForm<z.infer<typeof schema>>(...)) is unsound and assumes the input & output types are identical. When this isn't the case, you'll get errors like the ones you're experiencing. The Zod 4 changes to z.coerce change is now revealing this issue for more people. Drop the explicit generic and everything will work.
@colinhacks Thanks, removing the generic type passed to useForm did clear the error. However the returned values from useForm are not properly typed anymore. For example: form.getFieldState doesn't have the field name typed as passing the generic type. The same happens with control, which makes the type for the field become any.
- This is not passing the generic
- This is passing the generic
Removing the generic works for me as well. However type for my number input doesn't resolve correctly.
Type '{ onChange: (...event: any[]) => void; onBlur: Noop; value: unknown; disabled?: boolean | undefined; name: "age"; ref: RefCallBack; type: "number"; placeholder: string; }' is not assignable to type 'InputHTMLAttributes<HTMLInputElement>'.
Types of property 'value' are incompatible.
Type 'unknown' is not assignable to type 'string | number | readonly string[] | undefined'. [2322]
My input component:
<Input type='number' placeholder="shadcn" {...field} />
cc @quocluongha @wengkhing I believe all of this is working as intended. These inferred types are correct.
If you want to modify the input type for a coerced schema, you can do this in Zod 4:
z.coerce.string<string>()
// input and output type are both `string`
If you believe there is any incorrect behavior, please open a new issue with a fresh repro. 👍