-
-
Notifications
You must be signed in to change notification settings - Fork 192
feat: zod v4 support #768 #776
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Adds support for Zod v4 by introducing a new zodResolverV4
and preserving the existing resolver.
- Introduces
zodv4.ts
with a resolver that uses a Zod v4 alias - Updates
index.ts
to export bothzodResolver
andzodResolverV4
- Adjusts
package.json
to install an aliased Zod v4 and bumps the existing Zod version - Cleans up duplicate imports in typebox tests
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
File | Description |
---|---|
zod/src/zodv4.ts | Implements zodResolverV4 using the aliased Zod |
zod/src/index.ts | Exports original resolver and adds the v4 alias |
typebox/src/tests/typebox.ts | Removes duplicate imports in tests |
package.json | Bumps Zod dev dep and adds zod-v4 alias |
zod/src/zodv4.ts
Outdated
ResolverSuccess, | ||
appendErrors, | ||
} from 'react-hook-form'; | ||
import { ZodError, z } from 'zod-v4/v4'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The import path 'zod-v4/v4' is unusual and may not resolve correctly. Consider importing directly from the aliased package (e.g. import { ZodError, z } from 'zod-v4';
).
import { ZodError, z } from 'zod-v4/v4'; | |
import { ZodError, z } from 'zod-v4'; |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It needs to be done that way to work.
@@ -1 +1,2 @@ | |||
export * from './zod'; | |||
export { zodResolver } from './zod'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replacing export *
with named exports removes other exports from ./zod
. If consumers rely on additional types or utilities, re-export them too or restore export *
.
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do it this way to be able to export both resolvers of both versions.
package.json
Outdated
}, | ||
"peerDependencies": { | ||
"react-hook-form": "^7.55.0" | ||
}, | ||
"dependencies": { | ||
"@standard-schema/utils": "^0.3.0" | ||
"@standard-schema/utils": "^0.3.0", | ||
"zod-v4": "npm:zod@^3.25.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The alias zod-v4
points to zod@^3.25.0, which is still v3. To install Zod v4, update this alias to a ^4.x
version.
"zod-v4": "npm:zod@^3.25.0" | |
"zod-v4": "npm:zod@^4.x" |
Copilot uses AI. Check for mistakes.
package.json
Outdated
}, | ||
"peerDependencies": { | ||
"react-hook-form": "^7.55.0" | ||
}, | ||
"dependencies": { | ||
"@standard-schema/utils": "^0.3.0" | ||
"@standard-schema/utils": "^0.3.0", | ||
"zod-v4": "npm:zod@^3.25.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a dev dependency, like all the other schema libraries
/** | ||
* Creates a resolver function for react-hook-form that validates form data using a Zod schema | ||
* @param {z.ZodSchema<Input>} schema - The Zod schema used to validate the form data | ||
* @param {Partial<z.ParseParams>} [schemaOptions] - Optional configuration options for Zod parsing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update
* @param {Partial<z.ParseParams>} [schemaOptions] - Optional configuration options for Zod parsing | |
* @param {z.core.ParseContext<z.core.$ZodIssue>} [schemaOptions] - Optional configuration options for Zod parsing |
zod/src/zodv4.ts
Outdated
export function zodResolver<Input extends FieldValues, Context, Output>( | ||
schema: z.ZodSchema<Output, Input>, | ||
schemaOptions?: Partial<z.core.ParseContext<z.core.$ZodIssue>>, | ||
resolverOptions?: { | ||
mode?: 'async' | 'sync'; | ||
raw?: false; | ||
}, | ||
): Resolver<Input, Context, Output>; | ||
|
||
export function zodResolver<Input extends FieldValues, Context, Output>( | ||
schema: z.ZodSchema<Output, Input>, | ||
schemaOptions: Partial<z.core.ParseContext<z.core.$ZodIssue>> | undefined, | ||
resolverOptions: { | ||
mode?: 'async' | 'sync'; | ||
raw: true; | ||
}, | ||
): Resolver<Input, Context, Input>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these split into separate overloads? Odd considering their return types are identical.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the reason is that
- in the
raw: true
case, the output type isResolver<Input, Context, Input>
—the original input is returned - whereas in the opposite case (
resolverOptions.raw
is omitted or false) then the output type isResolver<Input, Context, Output>
.
I suggested the overload in #753 (comment), because I believe without it it’s not possible to express this kind of “conditional return type”
zod/src/zodv4.ts
Outdated
ResolverSuccess, | ||
appendErrors, | ||
} from 'react-hook-form'; | ||
import { ZodError, z } from 'zod-v4/v4'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tooling like this should only be importing from "/v4/core"
. This way you can support Zod (Regular) and Zod Mini schemas simultaneously. See https://zod.dev/library-authors
zod/src/zodv4.ts
Outdated
): Resolver<Input, Context, Output>; | ||
|
||
export function zodResolver<Input extends FieldValues, Context, Output>( | ||
schema: z.ZodSchema<Output, Input>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be z.core.$ZodType
to allow for Zod Mini schemas
zod/src/zodv4.ts
Outdated
return async (values: Input, _, options) => { | ||
try { | ||
const data = await schema[ | ||
resolverOptions.mode === 'sync' ? 'parse' : 'parseAsync' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After switching over to z.core.$ZodType
, you'll need to use the top level z.parse
and z.parseAsync
functions here. The $ZodType
base class has no methods.
Thanks for the review @colinhacks 🙌 I've uploaded the changes in the last commit. |
thanks @colinhacks for the review 🙏 |
@@ -5,6 +5,7 @@ | |||
"name": "@hookform/resolvers", | |||
"dependencies": { | |||
"@standard-schema/utils": "^0.3.0", | |||
"zod-v4": "npm:zod@^3.25.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lock file also needs to be updated after moving zod-v4 to devDependencies
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lock file also needs to be updated after moving zod-v4 to devDependencies
Shouldn't zod-v4
be under devDependencies? Only the standard schema is included as a dependency.
ResolverSuccess, | ||
appendErrors, | ||
} from 'react-hook-form'; | ||
import { ZodError } from 'zod-v4/v4'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think for v4-mini compatibility, the code should use core.$ZodError
instead.
export function zodResolver<Input extends FieldValues, Context, Output>( | ||
schema: core.$ZodType<Output, Input>, | ||
schemaOptions?: Partial<core.ParseContext<core.$ZodIssue>>, | ||
resolverOptions?: { | ||
mode?: 'async' | 'sync'; | ||
raw?: false; | ||
}, | ||
): Resolver<Input, Context, Output>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it seems like the overload for raw: true
was incorrectly removed, which breaks the types when this option is passed @alexcraviotto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see #776 (comment)
@@ -54,7 +55,7 @@ | |||
"vite-tsconfig-paths": "^5.1.4", | |||
"vitest": "^3.0.9", | |||
"yup": "^1.6.1", | |||
"zod": "^3.24.2", | |||
"zod": "3.24.4", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixing @CHC383 's suggestion by moving zod-v4
to devDependencies
"zod": "3.24.4", | |
"zod": "3.24.4", | |
"zod-v4": "npm:zod@^3.25.0", |
Thanks a lot @alexcraviotto for your contribution. Closing in favor of #777 |
Support for Zod v4 with
zodResolverV4
This PR adds support for the new version of Zod (v4) by introducing a new resolver:
zodResolverV4
. This allows users to work with schemas written using the latest version of Zod while maintaining compatibility with older implementations.To ensure backward compatibility, the original
zodResolver
has not been removed or modified.Due to issues related to tests in
typeschema.ts
, I’ve temporarily installed two separate versions of Zod (zod
andzod-v4
) to avoid breaking existing functionality. Ideally, in the future, it would be great to update those parts to also use the latest version of Zod.Usage
Using the new resolver is simple. You just need to import and use
zodResolverV4
like so:Big thanks to @hukpo for mentioning this solution in Issue #768 🙌