TypeScript合并泛型Zod Schema出现类型错误,如何解决?
解决Zod Schema合并后对象类型推断不匹配问题
问题分析
你遇到的类型错误本质是Zod内部对对象Schema的可选/必填属性做了复杂的类型转换(比如addQuestionMarks这类内部工具类型),导致TypeScript无法自动识别手动扩展的对象与合并后Schema的推断类型是兼容的。虽然类型断言可以跳过检查,但我们可以通过明确类型定义来让TypeScript正确推断。
解决方案
核心思路是手动定义合并后的类型为原Schema推断类型与版本Schema推断类型的交叉类型,而不是依赖合并后Schema的自动推断。这样TypeScript能清晰识别扩展后的对象符合该类型,同时合并后的Schema依然保持运行时校验能力。
修改后的代码如下:
import { z } from "zod"; // 版本化项的通用Schema const versioningSchema = z.object({ version: z.number(), }); export const addVersioningToItem = <U extends z.ZodRawShape>( originalSchema: z.ZodObject<U>, item: z.infer<typeof originalSchema>, ) => { // 手动定义合并后的类型:原类型与版本类型的交叉 type CombinedSchema = z.infer<typeof originalSchema> & z.infer<typeof versioningSchema>; const mergedSchema = originalSchema.merge(versioningSchema); // 此时TypeScript能正确识别该对象符合CombinedSchema类型 const itemWithVersioning: CombinedSchema = { ...item, version: 1, }; return { mergedSchema, itemWithVersioning }; };
为什么这样有效
- 交叉类型
A & B直接明确了合并后类型的结构,TypeScript可以轻松验证{...item, version:1}满足该结构 mergedSchema的推断类型与CombinedSchema完全等价,后续用mergedSchema做运行时校验不会有任何问题- 避免了依赖Zod内部复杂的类型转换逻辑,让类型推断更直接、可靠
额外优化(可选)
如果想进一步约束原Schema不能包含version属性(避免冲突),可以修改泛型约束:
export const addVersioningToItem = <U extends z.ZodRawShape & { version?: never }>( originalSchema: z.ZodObject<U>, item: z.infer<typeof originalSchema>, ) => { // ... 其余代码不变 };
这样如果传入的原Schema已经有version属性,TypeScript会提前报错,避免运行时的Schema合并冲突。
内容的提问来源于stack exchange,提问作者Tom Roberts
相关产品推荐
相关产品推荐

