如何用Zod实现对象至少一个属性通过验证?
Zod 实现“至少一个属性符合规则”的验证方案
你之前的写法问题在于:先定义了要求name和email必须同时符合各自规则的对象 schema,所以只要其中一个属性不满足(比如name长度不足),在进入refine之前就会触发验证错误,根本走不到后续的判断逻辑;而且你的refine仅检查属性是否存在,没有验证属性是否符合规则。
下面是两种优雅的实现方式:
方案一:可选属性 + 精细化校验(推荐)
先将两个属性设为可选,再通过refine结合safeParse检查至少一个属性符合自身规则:
// 抽离单个属性的验证规则,提升复用性 const validName = z.string().min(3); const validEmail = z.string().min(3); const userSchema = z.object({ name: validName.optional(), email: validEmail.optional() }).refine( (data) => { // 验证name是否符合规则,或email是否符合规则 return validName.safeParse(data.name).success || validEmail.safeParse(data.email).success; }, { message: "必须提供至少3个字符的姓名,或至少3个字符的邮箱", // 可选:指定错误路径,让错误提示更精准 path: [] } );
这种方式的优势:
- 允许对象仅包含
name或email中的一个 - 仅当两个属性都不符合规则(或都不存在)时,才会抛出验证错误
- 错误提示清晰,用户能明确知道需要满足的条件
方案二:联合类型分支校验
如果希望明确拆分两种合法场景(有合法name,或有合法email),可以使用z.union:
const userSchema = z.union([ // 场景1:包含符合规则的name,email可选(无需验证) z.object({ name: z.string().min(3) }).partial({ email: true }), // 场景2:包含符合规则的email,name可选(无需验证) z.object({ email: z.string().min(3) }).partial({ name: true }) ]);
如果需要严格限制另一个属性不能存在,可以把partial替换为omit:
// 仅允许存在name,不允许有email属性 z.object({ name: z.string().min(3) }).omit({ email: true })
内容的提问来源于stack exchange,提问作者Korer
相关产品推荐
相关产品推荐

