So I'm trying to make a helper that will allow me to easily create empty/initial form values from a zod schema that will validate the whole/complete form. In other words I want the schema to require every field to be populated, but initial values might be nullable...
Anyway I am confused by an issue demonstrated in this sandbox
With the following code:
const schema = z.object({
deep: z.object({
union: z.enum(['a', 'b'])
})
})
function makeObj<D extends Partial<z.infer<typeof schema>>, S extends z.ZodTypeAny>(schema: S, v: D): z.ZodType<DeepReplace<z.infer<S>, D>> {
return schema as z.ZodType<DeepReplace<z.infer<S>, D>>
}
const obj = makeObj(schema, {
deep: {
union: 'a'
}
}).parse({})
obj
is correctly typed:
const obj: {
deep: {
union: "a";
};
}
But if I replace the function declaration with this line:
function makeObj<D extends Partial<z.infer<S>>, S extends z.ZodTypeAny>(schema: S, v: D): z.ZodType<DeepReplace<z.infer<S>, D>> {
return schema as z.ZodType<DeepReplace<z.infer<S>, D>>
}
const obj = makeObj(schema, {
deep: {
union: 'a'
}
}).parse({})
Now type inference is broken:
const obj: {
deep: {
union: null;
} | {
union: "a" | "b";
};
}
Unless, I have found I put "as const" on the second argument:
const obj = makeObj(schema, {
deep: {
union: 'a'
}
} as const).parse({})
- It appears that this is only a problem when union types are involved
- I'd love not to have to bother with the
as const
everywhere. - And mostly I'd like to understand why using z.infer<> is the source of the issue!
Thanks!
-Morgan