Skip to content

Commit 02b2f70

Browse files
committed
Add overloads for zod resolver to handle schemaOptions.raw
1 parent 8c9d0d1 commit 02b2f70

File tree

2 files changed

+50
-8
lines changed

2 files changed

+50
-8
lines changed

zod/src/__tests__/zod.ts

+27
Original file line numberDiff line numberDiff line change
@@ -154,4 +154,31 @@ describe('zodResolver', () => {
154154
}>
155155
>();
156156
});
157+
158+
it('should correctly infer the output type from a zod schema using a transform with schemaOptions.raw', () => {
159+
const resolver1 = zodResolver(
160+
z.object({ id: z.number().transform((val) => String(val)) }),
161+
undefined,
162+
{ raw: true },
163+
);
164+
expectTypeOf(resolver1).toEqualTypeOf<
165+
Resolver<{ id: number }, unknown, { id: number }>
166+
>();
167+
168+
const resolver2 = zodResolver(
169+
z.object({ id: z.number().transform((val) => String(val)) }),
170+
{},
171+
{ raw: false },
172+
);
173+
expectTypeOf(resolver2).toEqualTypeOf<
174+
Resolver<{ id: number }, unknown, { id: string }>
175+
>();
176+
177+
const resolver3 = zodResolver(
178+
z.object({ id: z.number().transform((val) => String(val)) }),
179+
);
180+
expectTypeOf(resolver3).toEqualTypeOf<
181+
Resolver<{ id: number }, unknown, { id: string }>
182+
>();
183+
});
157184
});

zod/src/zod.ts

+23-8
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,26 @@ function parseErrorSchema(
8181
* resolver: zodResolver(schema)
8282
* });
8383
*/
84-
export function zodResolver<
85-
Input extends FieldValues,
86-
Context,
87-
Output,
88-
>(
84+
// passing `resolverOptions.raw: false` (or omitting) you get the transformed output type
85+
export function zodResolver<Input extends FieldValues, Context, Output>(
86+
schema: z.ZodSchema<Output, any, Input>,
87+
schemaOptions?: Partial<z.ParseParams>,
88+
resolverOptions?: {
89+
mode?: 'async' | 'sync';
90+
raw?: false;
91+
},
92+
): Resolver<Input, Context, Output>
93+
// passing `resolverOptions.raw: true` you get back the input type
94+
export function zodResolver<Input extends FieldValues, Context, Output>(
95+
schema: z.ZodSchema<Output, any, Input>,
96+
schemaOptions: Partial<z.ParseParams> | undefined,
97+
resolverOptions: {
98+
mode?: 'async' | 'sync';
99+
raw: true;
100+
},
101+
): Resolver<Input, Context, Input>
102+
// implementation
103+
export function zodResolver< Input extends FieldValues, Context, Output>(
89104
schema: z.ZodSchema<Output, any, Input>,
90105
schemaOptions?: Partial<z.ParseParams>,
91106
resolverOptions: {
@@ -95,7 +110,7 @@ export function zodResolver<
95110
): Resolver<
96111
Input,
97112
Context,
98-
Output
113+
Output | Input // consumers never see this type; they only see types from overload signatures
99114
> {
100115
return async (values: Input, _, options) => {
101116
try {
@@ -107,8 +122,8 @@ export function zodResolver<
107122

108123
return {
109124
errors: {},
110-
values: data,
111-
} satisfies ResolverSuccess<Output>;
125+
values: resolverOptions.raw ? Object.assign({}, values) : data,
126+
} satisfies ResolverSuccess<Input | Output>;
112127
} catch (error) {
113128
if (isZodError(error)) {
114129
return {

0 commit comments

Comments
 (0)