Zod中扩展类型联合解析为基础类型的问题求助
问题原因与解决方案
核心原因
Zod的联合类型(z.union)是按顺序尝试匹配Schema的:只要数据通过了某一个Schema的验证,就会直接用该Schema解析,不会继续检查后续的Schema。
你的场景中,typeA是typeB的子集——所有符合typeB的数据都满足typeA的结构要求,这就导致了两个问题:
- 当
typeA排在联合列表前面时,typeB的数据会被typeA优先匹配,而Zod的object默认会剥离未定义的字段,所以extraProp会被移除。 - 当
typeB排在前面时,错误的extraProp(比如数字4)会让typeB验证失败,随后自动fallback到typeA,同样会剥离错误字段,不会触发预期的报错。
解决方案
方案1:让typeA严格拒绝额外字段
给typeA添加strict()方法,这样当数据包含extraProp这类未定义字段时,typeA会验证失败,转而尝试匹配typeB:
const typeA = z.object({ prop: z.string() }).strict(); const typeB = typeA.extend({ extraProp: z.boolean(), }); const schema = z.array(z.union([typeA, typeB])); // 正确解析typeB数据 schema.parse([{ prop: 'foo', extraProp: true }]); // 输出:[{ "prop": "foo", "extraProp": true }] // 错误数据触发报错 schema.parse([{ prop: 'foo', extraProp: 4 }]); // 抛出ZodError:extraProp必须是布尔值
方案2:使用区分式联合(z.discriminatedUnion)
如果你的数据可以添加一个用来区分类型的字段(比如type),推荐使用discriminatedUnion,它会直接根据区分字段匹配对应的Schema,完全避免顺序问题:
const typeA = z.object({ type: z.literal('A'), prop: z.string(), }); const typeB = z.object({ type: z.literal('B'), prop: z.string(), extraProp: z.boolean(), }); const schema = z.array(z.discriminatedUnion('type', [typeA, typeB])); // 正确解析typeB数据 schema.parse([{ type: 'B', prop: 'foo', extraProp: true }]); // 错误数据触发报错 schema.parse([{ type: 'B', prop: 'foo', extraProp: 4 }]); // 抛出ZodError:extraProp类型错误
内容的提问来源于stack exchange,提问作者fZab
相关产品推荐
相关产品推荐

