如何在 Zod 中根据字段值动态调整 Schema 结构?

酷磊君_8505

酷磊君_8505

2026-07-19

766人浏览

原创

如何在 Zod 中根据字段值动态调整 Schema 结构?

本文介绍使用 Zod 的 Discriminated Union(判别式联合)实现条件化 Schema:当某个布尔字段(如 showShippingAddress)为 true 时,强制校验关联字段;为 false 时则忽略这些字段,避免冗余 .superRefine() 手动校验。

本文介绍使用 zod 的 discriminated union(判别式联合)实现条件化 schema:当某个布尔字段(如 `showshippingaddress`)为 true 时,强制校验关联字段;为 false 时则忽略这些字段,避免冗余 `.superrefine()` 手动校验。

在表单验证中,常需根据用户选择(如是否启用配送地址)动态控制后续字段的必填性与校验规则。Zod 原生不支持“运行时条件 Schema”,但通过 Discriminated Union(判别式联合) 可优雅实现该需求——它基于一个固定字面量字段(discriminator),将整个对象划分为互斥的、结构明确的子 Schema。

核心思路是:将 showShippingAddress 字段定义为 z.literal(true) 或 z.literal(false),而非泛化的 z.boolean(),从而让 Zod 能静态识别并路由到对应分支。

以下是一个完整、可直接使用的示例:

import { z } from 'zod';

const formSchema = z.discriminatedUnion('showShippingAddress', [
  // 分支一:不显示配送地址
  z.object({
    showShippingAddress: z.literal(false),
    field1: z.string().nonempty('请输入字段1'),
    field2: z.string().nonempty('请输入字段2'),
    // field3 和 field4 在此分支中完全不存在(非 optional,而是彻底移除)
    // 若需兼容旧数据或 API,可显式设为 optional,但语义上更推荐彻底排除
  }),
  // 分支二:显示配送地址 → field3、field4 变为必填且带额外校验
  z.object({
    showShippingAddress: z.literal(true),
    field1: z.string().nonempty('请输入字段1'),
    field2: z.string().nonempty('请输入字段2'),
    field3: z.string().nonempty('配送地址不能为空'),
    field4: z.string()
      .nonempty('邮编不能为空')
      .regex(/^\d{6}$/, '请填写6位中国邮政编码'),
  }),
]);

// ✅ 正确解析(showShippingAddress = false)
formSchema.parse({
  showShippingAddress: false,
  field1: '张三',
  field2: '13800138000',
});

// ✅ 正确解析(showShippingAddress = true,且所有字段完整)
formSchema.parse({
  showShippingAddress: true,
  field1: '李四',
  field2: '13900139000',
  field3: '北京市朝阳区建国路1号',
  field4: '100022',
});

// ❌ 校验失败:showShippingAddress = true 但缺少 field3
// formSchema.parse({ showShippingAddress: true, field1: 'A', field2: 'B' }); // 报错

// ❌ 校验失败:field4 不符合正则
// formSchema.parse({ showShippingAddress: true, field1: 'A', field2: 'B', field3: 'X', field4: '123' }); // 报错

⚠️ 关键注意事项:

  • discriminator 字段必须是 literal 类型(如 z.literal(true)),不能用 z.boolean(),否则 Zod 无法静态区分分支;
  • 每个分支应完全独立定义字段:不需要的字段不要声明为 .optional(),而应彻底省略——这能提升类型安全性和 IDE 自动补全精度;
  • 若后端 API 允许 field3/field4 在 showShippingAddress: false 时存在(如历史数据兼容),才考虑在 false 分支中添加 .optional(),但需权衡语义清晰度;
  • 所有公共字段(如 field1, field2)必须在每个分支中重复定义,确保类型一致性;
  • 使用 .nonempty() 替代 .nullable().min(1),语义更准确且避免空字符串通过校验。

相比手动 superRefine,判别式联合的优势在于:
✅ 类型推导精准(TypeScript 可精确识别各分支的 shape)
✅ 错误信息更清晰(Zod 直接指出“缺少 required field”而非自定义 message)
✅ 无运行时逻辑膨胀(无需维护大量 if 校验块)
✅ 支持嵌套、组合与复用(可将分支 Schema 提取为常量)

综上,面对“字段依赖布尔开关”的场景,优先选用 z.discriminatedUnion —— 它是 Zod 官方推荐、类型安全、可维护性高的标准解法。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

2026.09.30

20

10

LLVM RISC-V参数配置教程
LLVM RISC-V参数配置教程

本专题介绍LLVM对RISC-V基础ISA和扩展的支持方式,涵盖RV32、RV64、标准扩展、实验性扩展、厂商扩展、-menable-experimental-extensions和版本差异。

2026.09.30

40

14

LLVM IR中间表示入门指南
LLVM IR中间表示入门指南

本专题整理LLVM IR的核心概念,包括中间表示作用、模块结构、函数、基本块、SSA形式、类型系统和常见语法,帮助新手理解LLVM编译流程中的关键层。

2026.09.30

20

12

PDF转图片方法
PDF转图片方法

需要把 PDF 页面用于上传、预览、分享或图片归档时,PDF 转图片方法专题整理 JPG/PNG 格式选择、逐页导出、清晰度设置、批量下载和结果检查等流程,帮助用户稳定完成 PDF 图片化处理。

2026.09.30

20

26

PixTV AI视频生成与无限画布创作
PixTV AI视频生成与无限画布创作

PixTV专题整理AI视频与视觉内容创作相关功能使用教程,涵盖AI生图、视频生成、无限画布、多模型创作、素材管理、声音音乐及视频剪辑等功能,帮助用户快速掌握PixTV从创意到成片的完整制作方法。

2026.09.29

20

15

Buffalo框架数据库开发全教程
Buffalo框架数据库开发全教程

本专题围绕Buffalo框架数据库开发,讲解database.yml多环境配置、soda与fizz迁移生成回滚、模型结构体标签、增删改查与条件查询、一对多与多对多关联、数据校验、回调钩子、事务处理及原生SQL执行能力。

2026.09.23

240

15

Buffalo框架路由与请求处理实操指南
Buffalo框架路由与请求处理实操指南

本专题讲解Buffalo框架路由与请求处理机制,涵盖路由注册与分组、资源路由、Handler编写规范、Context上下文方法、参数绑定、中间件编写挂载、Session与Cookie读写、Flash消息及错误页面定制方法。

2026.09.23

140

15

Buffalo框架零基础入门教程
Buffalo框架零基础入门教程

本专题整理Buffalo框架入门内容,涵盖Go环境准备、buffalo CLI安装、新项目生成、目录结构说明、dev热加载启动、数据库连接配置与常见报错排查,帮助新手按约定优于配置的思路跑通第一个Buffalo框架应用。

2026.09.23

120

15

Conan创建软件包配方指南
Conan创建软件包配方指南

本专题介绍通过conanfile.py创建软件包的方法,讲解包名、版本、依赖和构建设置等基础信息,以及source、build、package、package_info等常用方法的作用及编写思路。

2026.09.22

60

12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.4万人学习