From 10dfbe56a4d6c85855dd4e498cc5afab3ea345b1 Mon Sep 17 00:00:00 2001 From: Shion Daimon Date: Tue, 10 Feb 2026 11:15:01 +0900 Subject: [PATCH 1/3] fix(zod): relax zod v4 resolver schema typing Switch zodResolver v4 overloads from strict $ZodType internals to structural _zod-based schema typing so mixed zod type resolutions no longer fail overload matching. Co-authored-by: Cursor --- zod/src/zod.ts | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/zod/src/zod.ts b/zod/src/zod.ts index 9093c81..7b543f3 100644 --- a/zod/src/zod.ts +++ b/zod/src/zod.ts @@ -148,6 +148,30 @@ interface Zod3Type { typeName: string; }; } +type Zod4TypeLike = { + _zod: { + input?: unknown; + output?: unknown; + }; +}; +type Zod4SchemaLike = { + _zod: { + input: Input; + output: Output; + }; +}; +type Zod4Input = T extends { + _zod: { input?: infer I }; +} + ? I extends FieldValues + ? I + : FieldValues + : FieldValues; +type Zod4Output = T extends { + _zod: { output?: infer O }; +} + ? O + : unknown; // some type magic to make versions pre-3.25.0 still work type IsUnresolved = PropertyKey extends keyof T ? true : false; @@ -197,26 +221,32 @@ export function zodResolver( resolverOptions: RawResolverOptions, ): Resolver; // the Zod 4 overloads need to be generic for complicated reasons +export function zodResolver< + Context, + T extends Zod4TypeLike, +>( + schema: T, + schemaOptions?: Zod4ParseParams, // already partial + resolverOptions?: NonRawResolverOptions, +): Resolver, Context, Zod4Output>; export function zodResolver< Input extends FieldValues, Context, Output, - T extends z4.$ZodType = z4.$ZodType, >( - schema: T, + schema: Zod4SchemaLike, schemaOptions?: Zod4ParseParams, // already partial resolverOptions?: NonRawResolverOptions, -): Resolver, Context, z4.output>; +): Resolver; export function zodResolver< Input extends FieldValues, Context, Output, - T extends z4.$ZodType = z4.$ZodType, >( - schema: z4.$ZodType, + schema: Zod4SchemaLike, schemaOptions: Zod4ParseParams | undefined, // already partial resolverOptions: RawResolverOptions, -): Resolver, Context, z4.input>; +): Resolver; /** * Creates a resolver function for react-hook-form that validates form data using a Zod schema * @param {z3.ZodSchema} schema - The Zod schema used to validate the form data From b05970e1ec9287a0c8a4a7f1cbe543f36ee1d894 Mon Sep 17 00:00:00 2001 From: Shion Daimon Date: Tue, 10 Feb 2026 11:38:18 +0900 Subject: [PATCH 2/3] style(zod): apply formatter output to overload declarations Normalize multiline generic declarations in zod resolver overload signatures after biome auto-format. Co-authored-by: Cursor --- zod/src/zod.ts | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/zod/src/zod.ts b/zod/src/zod.ts index 7b543f3..909ebb5 100644 --- a/zod/src/zod.ts +++ b/zod/src/zod.ts @@ -221,28 +221,17 @@ export function zodResolver( resolverOptions: RawResolverOptions, ): Resolver; // the Zod 4 overloads need to be generic for complicated reasons -export function zodResolver< - Context, - T extends Zod4TypeLike, ->( +export function zodResolver( schema: T, schemaOptions?: Zod4ParseParams, // already partial resolverOptions?: NonRawResolverOptions, ): Resolver, Context, Zod4Output>; -export function zodResolver< - Input extends FieldValues, - Context, - Output, ->( +export function zodResolver( schema: Zod4SchemaLike, schemaOptions?: Zod4ParseParams, // already partial resolverOptions?: NonRawResolverOptions, ): Resolver; -export function zodResolver< - Input extends FieldValues, - Context, - Output, ->( +export function zodResolver( schema: Zod4SchemaLike, schemaOptions: Zod4ParseParams | undefined, // already partial resolverOptions: RawResolverOptions, From 34743c2a995e6dbac7be141f8ea8b2170b041862 Mon Sep 17 00:00:00 2001 From: Shion Daimon Date: Fri, 20 Feb 2026 14:09:15 +0900 Subject: [PATCH 3/3] test(zod): add structural overload type inference coverage --- zod/src/__tests__/zod-v4-mini.ts | 17 +++++++++++++++++ zod/src/__tests__/zod-v4.ts | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/zod/src/__tests__/zod-v4-mini.ts b/zod/src/__tests__/zod-v4-mini.ts index 54c5681..1787717 100644 --- a/zod/src/__tests__/zod-v4-mini.ts +++ b/zod/src/__tests__/zod-v4-mini.ts @@ -111,6 +111,23 @@ describe('zodResolver', () => { >(); }); + it('should infer resolver types from a Zod v4 mini structural schema type', () => { + type StructuralSchema = { + _zod: { + input: { id: number }; + output: { id: string }; + }; + }; + + type InferredResolver = ReturnType< + typeof zodResolver + >; + + expectTypeOf().toEqualTypeOf< + Resolver<{ id: number }, unknown, { id: string }> + >(); + }); + it('should correctly infer the output type from a zod schema using a transform', () => { const resolver = zodResolver( z.object({ diff --git a/zod/src/__tests__/zod-v4.ts b/zod/src/__tests__/zod-v4.ts index 0a043bc..ec04d1b 100644 --- a/zod/src/__tests__/zod-v4.ts +++ b/zod/src/__tests__/zod-v4.ts @@ -118,6 +118,23 @@ describe('zodResolver', () => { >(); }); + it('should infer resolver types from a Zod v4 structural schema type', () => { + type StructuralSchema = { + _zod: { + input: { id: number }; + output: { id: string }; + }; + }; + + type InferredResolver = ReturnType< + typeof zodResolver + >; + + expectTypeOf().toEqualTypeOf< + Resolver<{ id: number }, unknown, { id: string }> + >(); + }); + it('should correctly infer the output type from a zod schema using a transform', () => { const resolver = zodResolver( z.object({ id: z.number().transform((val) => String(val)) }),