Combining multiple schemas with generic type #3483
-
So, I have a generic function where I need to combine an arbitrary number of schemas. It should look something like this: // ideally, we would be able to infer the types of the schemas from a rest parameter:
function idealCombineSchemas(...schemas: AnyZodObject[]) {
let combined = schemas[0]
for (let i = 1; i < schemas.length; i++) {
combined = combined.merge(schemas[i])
}
return combined
}
const IdealCombinedSchema = idealCombineSchemas(schema1, schema2, schema3)
type IdealCombinedType = z.infer<typeof IdealCombinedSchema>
// this does not give proper type:
// type IdealCombinedType = { [x: string]: any } However, this doesn't work. You have to infer each schema individually, like this: const schema1 = z.object({ key1: z.string() })
const schema2 = z.object({ key2: z.string() })
const schema3 = z.object({ key3: z.date() })
type extend2Shapes<A extends object, B extends object> = {
[K in keyof A as K extends keyof B ? never : K]: A[K]
} & {
[K in keyof B]: B[K]
}
type extend3Shapes<A extends object, B extends object, C extends object> = {
[K in keyof A as K extends keyof B
? never
: K extends keyof C
? never
: K]: A[K]
} & {
[K in keyof B]: B[K]
} & {
[K in keyof C]: C[K]
}
type extend4Shapes<
A extends object,
B extends object,
C extends object,
D extends object,
> = {
[K in keyof A as K extends keyof B
? never
: K extends keyof C
? never
: K extends keyof D
? never
: K]: A[K]
} & {
[K in keyof B]: B[K]
} & {
[K in keyof C]: C[K]
} & {
[K in keyof D]: D[K]
}
type extend5Shapes<
A extends object,
B extends object,
C extends object,
D extends object,
E extends object,
> = {
[K in keyof A as K extends keyof B
? never
: K extends keyof C
? never
: K extends keyof D
? never
: K extends keyof E
? never
: K]: A[K]
} & {
[K in keyof B]: B[K]
} & {
[K in keyof C]: C[K]
} & {
[K in keyof D]: D[K]
} & {
[K in keyof E]: E[K]
}
export function combineSchemas<T extends AnyZodObject, U extends AnyZodObject>(
s1: T,
s2: U,
): ZodObject<
extend2Shapes<T['shape'], U['shape']>,
T['_def']['unknownKeys'],
T['_def']['catchall']
>
export function combineSchemas<
T extends AnyZodObject,
U extends AnyZodObject,
V extends AnyZodObject,
A1 extends T['shape'],
A2 extends U['shape'],
A3 extends V['shape'],
>(
s1: T,
s2: U,
s3: V,
): ZodObject<
extend3Shapes<A1, A2, A3>,
T['_def']['unknownKeys'],
T['_def']['catchall']
>
export function combineSchemas<
T extends AnyZodObject,
U extends AnyZodObject,
V extends AnyZodObject,
W extends AnyZodObject,
A1 extends T['shape'],
A2 extends U['shape'],
A3 extends V['shape'],
A4 extends W['shape'],
>(
s1: T,
s2: U,
s3: V,
s4: W,
): ZodObject<
extend4Shapes<A1, A2, A3, A4>,
T['_def']['unknownKeys'],
T['_def']['catchall']
>
export function combineSchemas<
T extends AnyZodObject,
U extends AnyZodObject,
V extends AnyZodObject,
W extends AnyZodObject,
X extends AnyZodObject,
A1 extends T['shape'],
A2 extends U['shape'],
A3 extends V['shape'],
A4 extends W['shape'],
A5 extends X['shape'],
>(
s1: T,
s2: U,
s3: V,
s4: W,
s5: X,
): ZodObject<
extend5Shapes<A1, A2, A3, A4, A5>,
T['_def']['unknownKeys'],
T['_def']['catchall']
>
export function combineSchemas(...schemas: AnyZodObject[]) {
let combined = schemas[0]
for (let i = 1; i < schemas.length; i++) {
combined = combined.merge(schemas[i])
}
return combined as any
}
const CombinedSchema = combineSchemas(schema1, schema2, schema3)
// this gives proper type:
// type CombinedType = { key1: string; key2: string; key3: Date }
type CombinedType = z.infer<typeof CombinedSchema> I'm wondering if anyone has a better way to do this? |
Beta Was this translation helpful? Give feedback.
Answered by
zwhitchcox
May 10, 2024
Replies: 2 comments
-
Answered here: #3480 |
Beta Was this translation helpful? Give feedback.
0 replies
Answer selected by
zwhitchcox
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Answered here: #3480