Skip to content

Commit 6d6b694

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

File tree

2 files changed

+52
-3
lines changed

2 files changed

+52
-3
lines changed

zod/src/__tests__/zod.ts

Lines changed: 27 additions & 0 deletions
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

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,28 @@ function parseErrorSchema(
8181
* resolver: zodResolver(schema)
8282
* });
8383
*/
84+
// passing raw: false or omitting resolverOptions.raw 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<
93+
Input,
94+
Context,
95+
Output
96+
>
97+
// passing raw: true you get back the input type
98+
export function zodResolver<Input extends FieldValues, Context, Output>(
99+
schema: z.ZodSchema<Output, any, Input>,
100+
schemaOptions: Partial<z.ParseParams> | undefined,
101+
resolverOptions: {
102+
mode?: 'async' | 'sync';
103+
raw: true;
104+
},
105+
): Resolver<Input, Context, Input>
84106
export function zodResolver<
85107
Input extends FieldValues,
86108
Context,
@@ -95,7 +117,7 @@ export function zodResolver<
95117
): Resolver<
96118
Input,
97119
Context,
98-
Output
120+
Output | Input // implementation signature might return either; this is hidden from consumers
99121
> {
100122
return async (values: Input, _, options) => {
101123
try {
@@ -107,8 +129,8 @@ export function zodResolver<
107129

108130
return {
109131
errors: {},
110-
values: data,
111-
} satisfies ResolverSuccess<Output>;
132+
values: resolverOptions.raw ? Object.assign({}, values) : data,
133+
} satisfies ResolverSuccess<Input | Output>;
112134
} catch (error) {
113135
if (isZodError(error)) {
114136
return {

0 commit comments

Comments
 (0)