使用Zod的parse方法时,合法属性为何被移除?
Zod使用.or()时parse移除合法属性的原因与解决办法
问题场景
使用Zod的schema.parse验证输入时,发现合法属性被移除,问题出在.or()方法的使用上,示例代码如下:
const z = require('zod') const baseSchema = z.object({}) const extendedSchema = baseSchema.extend({ a: z.string() }) const optionsSchema = baseSchema.or(extendedSchema) const options = { a: 'A' } console.log('before `schema.parse`', JSON.stringify(options)) // 输出: before `schema.parse` {"a":"A"} const validOptions = optionsSchema.parse(options) console.log('-after `schema.parse`', JSON.stringify(validOptions)) // 输出: -after `schema.parse` {}
原因解析
这不是Zod的Bug,而是.or()(本质是Union类型)的工作机制导致的:
- Zod会按你传入的顺序依次尝试匹配Union中的每个Schema,一旦某个Schema匹配成功,就会立即用该Schema来解析输入并返回结果,不会再尝试后续的Schema。
- 示例中
baseSchema是一个空对象Schema,它能匹配任何对象(空对象Schema默认允许额外属性),但解析时会严格按照Schema的结构输出——也就是空对象。所以输入{a: 'A'}时,首先匹配上了baseSchema,直接输出空对象,完全不会走到extendedSchema的匹配逻辑。
解决办法
调整.or()中Schema的顺序,把更具体、约束更强的Schema放在前面,让Zod优先匹配更精准的规则:
// 调换顺序,先匹配带a属性的extendedSchema const optionsSchema = extendedSchema.or(baseSchema) const validOptions = optionsSchema.parse(options) console.log('-after `schema.parse`', JSON.stringify(validOptions)) // 输出: -after `schema.parse` {"a":"A"}
这样输入{a: 'A'}时,会先匹配到extendedSchema,解析后自然保留a属性;如果输入的是空对象,则会匹配到baseSchema,输出空对象,符合预期。
内容的提问来源于stack exchange,提问作者Shawn
相关产品推荐
相关产品推荐

