You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于表单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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 22:10:27