如何基于表单status字段实现Zod条件验证?
如何基于Zod中枚举字段的值动态变更验证规则
我有一个表单,其中包含status = 'DRAFT' | 'READY'的枚举字段,想基于该字段的值使用Zod库调整验证规则。具体需求如下:
- 当
status为"DRAFT"时,surname可以为null,验证通过 - 当
status为"READY"时,surname为null则验证失败(即此时surname需要满足.min(1)的规则)
当前的Schema代码:
const schema = z.object({ name: z.string(), surname: z.string().min(1), status: z.enum(["READY", "DRAFT"]) });
解决方案1:用z.discriminatedUnion(推荐)
这是Zod专门为这类分支验证场景设计的方案,代码结构清晰,类型推断也更准确:
// 定义公共字段的基础Schema const baseSchema = z.object({ name: z.string() }); // DRAFT状态下的Schema:surname允许为null或任意字符串 const draftSchema = baseSchema.extend({ surname: z.string().nullable(), status: z.literal("DRAFT") }); // READY状态下的Schema:surname必须是非空字符串 const readySchema = baseSchema.extend({ surname: z.string().min(1), status: z.literal("READY") }); // 合并为区分联合类型Schema const schema = z.discriminatedUnion("status", [draftSchema, readySchema]);
测试效果:
- 验证通过:
schema.parse({ name: "John", surname: null, status: "DRAFT" }); - 验证失败(READY状态下surname为null):
schema.parse({ name: "John", surname: null, status: "READY" }); // 抛出ZodError,提示surname不能为空字符串
解决方案2:用z.refine自定义验证逻辑
如果不想拆分Schema,也可以通过自定义验证规则实现需求:
const schema = z.object({ name: z.string(), surname: z.string().nullable(), // 先放宽类型,允许null或字符串 status: z.enum(["READY", "DRAFT"]) }).refine((data) => { // READY状态下,强制surname为非空字符串 if (data.status === "READY") { return typeof data.surname === "string" && data.surname.length >= 1; } // DRAFT状态下不做额外限制 return true; }, { message: "READY状态下surname不能为空", path: ["surname"] // 指定错误字段,方便表单展示错误提示 });
方案对比
discriminatedUnion:类型推断精准,代码结构清晰,适合多分支复杂场景,Zod会自动根据status的值推断出对应字段的类型refine:更灵活,适合简单的自定义验证逻辑,但可读性和类型推断能力不如前者
内容的提问来源于stack exchange,提问作者deithy
相关产品推荐
相关产品推荐

