news 2026/9/7 15:10:16

Zod 数据验证实践:从订单字段到接口解析,三个场景完成上手

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Zod 数据验证实践:从订单字段到接口解析,三个场景完成上手

Zod 数据验证实践:从订单字段到接口解析,三个场景完成上手

【免费下载链接】zodTypeScript-first schema validation with static type inference项目地址: https://gitcode.com/GitHub_Trending/zo/zod

周五晚上的一次线上告警:聊天消息的"回复关系"偶发丢失。排查后发现,后端悄悄把replyTo字段从字符串换成了数字,前端一直按字符串处理,问题暴露时脏数据已经流了半天。这类"接口契约与前端假设不一致"的坑,正是 TypeScript 数据验证最典型的用武之地:在数据进入业务的边界处,先用 Zod 按 schema 校验一遍,不合规则直接拦下,而不是让坏值一路渗透到深处。

为什么 Zod 值得进项目

一句话:schema 只写一份,类型由z.infer从 schema 推断出来——校验规则和类型同源,不用人工保持同步;运行时零依赖,打包体积基本可以忽略。

三十秒装好:先分清两种"过一遍"

这一节解决什么问题:数据进来之后,校验失败时到底该抛错还是该返回结果?先装:

npm install zod
import { z } from "zod"; const schema = z.object({ port: z.number().int() }); // 失败直接抛 ZodError,适合"必须对"的内部环节 const ok = schema.parse({ port: 8080 }); // 失败返回结果对象,方便取错误信息做展示 const res = schema.safeParse({ port: "8080" }); if (!res.success) { console.log(res.error.issues[0].message); }

区分口径很朴素:自己构造的数据用parse,来源不受控的数据用safeParse,把异常收敛在边界处。

官方文档里用这张图描述数据流向:未知输入穿过parse变成带类型的输出;图中decode/encode双向流是 v4 的 codec 模型,入门阶段知道有这条路径即可。

场景一:电商订单的嵌套结构与默认值

这一节解决什么问题:上游网关推来的订单,结构有嵌套、有可缺项,业务代码不能每处都手写?? []

const orderSchema = z.object({ orderNo: z.string().min(1), amount: z.number().nonnegative(), // 金额不允许为负 items: z.array(z.object({ sku: z.string(), quantity: z.number().int().min(1), })).min(1), shipTo: z.object({ name: z.string(), phone: z.string(), city: z.string().optional(), // 允许缺,传了必须是字符串 }), notes: z.string().optional(), tags: z.array(z.string()).default([]), // 缺省时兜底空数组 }); type Order = z.infer<typeof orderSchema>; // 用 schema 锁类型

为什么这么写:optional只表示"字段可以不出现",传进来之后仍是原始类型;default则由 Zod 主动补值,下游可以默认字段必在。把这两种语义在 schema 里分开表达,比在业务代码里到处补兜底更稳。

场景二:聊天消息的跨字段校验

这一节解决什么问题:单字段规则都过了,但"回复类消息却没有指向原消息"这种跨字段矛盾,schema 得会自己抓出来。

const messageSchema = z.object({ id: z.string(), type: z.enum(["text", "reply", "system"]), content: z.string().max(2000), createdAt: z.number(), // 毫秒时间戳 replyTo: z.string().optional(), // 原消息 id }).refine( (m) => m.type !== "reply" || Boolean(m.replyTo), { message: "reply 类型消息必须指定原消息", path: ["replyTo"] } );

注意这里:能写在字段上的规则就写在字段上,refine只留给需要"看一眼别的字段"的场景;path决定错误挂在哪个字段下,前端定位问题时更直观。

场景三:配置解析与强制转换

这一节解决什么问题:.env或配置接口里一切值都是字符串,"8080"不该在业务里再被Number()一遍。

const configSchema = z.object({ PORT: z.coerce.number().int().min(1).max(65535), // 字符串强转为数字 LOG_LEVEL: z.enum(["info", "warn", "error"]).default("info"), EXPIRES: z.coerce.date().optional(), // 日期字符串转 Date }); const cfg = configSchema.parse({ PORT: "8080", EXPIRES: "2026-12-31" }); console.log(typeof cfg.PORT, cfg.EXPIRES instanceof Date);

coerce的定位是"值本身没问题,只是类型不对"——配置解析、表单输入正是这种场景的日常,转换和校验在同一步完成。

新手避坑清单

这一节解决什么问题:前三个场景都跑通之后,下面几处仍是最容易翻车的地方。

  1. parse / safeParse 混用:在错误处理路径上用parse抛错,又在上层catch后吞掉,错误信息就丢了。来源不受控的数据一律safeParse
  2. 忘了z.infer锁类型:schema 改了一行,手写的类型定义没跟上,两边悄悄分叉。类型永远从 schema 推。
  3. 把 optional 当 nullableoptional只表示字段可缺;接口若可能显式传null,需要.nullable().nullish(),别指望optional替你接住null
  4. z.coerce.boolean()的"陷阱":v4 按真值判断,"false"会解析成true,只有空串、0undefinedfalse。配置开关建议写z.enum(["true", "false"])再自己转。

下一步可以做什么

这一节给三条最短的继续路径:

  • 把场景二里的type字段改用z.discriminatedUnion重写,体会按判别字段分流各子类型
  • 翻一翻 v4 classic 测试目录,每种写法的官方样例都在里面
  • 需要与外部工具对接时,查看 schema 的 JSON Schema 转换能力;若维护 v3 风格代码,可对照 v3 中文文档

【免费下载链接】zodTypeScript-first schema validation with static type inference项目地址: https://gitcode.com/GitHub_Trending/zo/zod

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/6 9:01:05

Logseq DB 版本指南:如何把你的笔记搬进实时协作知识库

Logseq DB 版本指南&#xff1a;如何把你的笔记搬进实时协作知识库 【免费下载链接】logseq A privacy-first, open-source platform for knowledge management and collaboration. Download link: http://github.com/logseq/logseq/releases. roadmap: https://logseq.io/p/NX…

作者头像 李华
网站建设 2026/9/6 0:46:59

STM32实战:基于FreeRTOS的智能仓储环境监测系统开发详解

简介&#xff1a;本资源是一套基于STM32F103C8T6的智能仓储环境监测系统完整工程实现&#xff0c;面向嵌入式初学者、课程设计学生及物联网实践开发者&#xff0c;解决小型仓储场景下温湿度、光照、烟雾等多参数实时感知与闭环调控问题。项目融合Proteus仿真与真实硬件逻辑&…

作者头像 李华
网站建设 2026/9/4 13:03:15

云从科技校招软件测试笔试题全解析:从AI测试到用例设计

1. 考题全景&#xff1a;先看清云从这份卷子在筛什么人 云从科技2020校招的软件测试笔试题&#xff0c;放在当时和现在来看都挺有代表性的。近几年AI视觉赛道扩张快&#xff0c;云从作为“AI四小龙”里偏B端和G端落地的一家公司&#xff0c;测试岗位的笔试题不是单纯背概念就能…

作者头像 李华
网站建设 2026/9/6 11:53:20

142、阻抗控制:力位混合控制的机器人交互

142、阻抗控制:力位混合控制的机器人交互 调试台上那台六轴机械臂又抖了。不是那种高频震颤,是那种低频的、带着闷响的、像人打寒颤一样的抖动。我盯着示波器上力传感器那条曲线,它正在以2赫兹左右的频率来回甩,幅度还不小。旁边实习生问了一句:“老师,是不是增益调太大…

作者头像 李华
网站建设 2026/9/3 17:51:09

React生态常用库指南:路由、状态、UI层选型实战

React 本身并不是一个全家桶框架。它只接管视图层&#xff0c;路由、状态、请求、表单、样式、测试&#xff0c;甚至移动端适配&#xff0c;都要靠周边库拼出来。很多开发者在学到组件、Props、Hooks 之后&#xff0c;进入真实项目时会突然发现选择太多&#xff1a;同一个功能至…

作者头像 李华
网站建设 2026/9/4 10:22:28

DBeaver数据导入提速实战:线程与批次调优完整指南

DBeaver数据导入提速实战:线程与批次调优完整指南 【免费下载链接】dbeaver Free universal database tool and SQL client 项目地址: https://gitcode.com/GitHub_Trending/db/dbeaver 周五晚上十一点,你在 DBeaver 里盯着数据导入的进度条,几十万行的表已经爬了半个多…

作者头像 李华