
Zod 数据校验指南5 分钟跑通 TypeScript 类型推断从入门到进阶【免费下载链接】zodTypeScript-first schema validation with static type inference项目地址: https://gitcode.com/GitHub_Trending/zo/zod你从前端拿到一份用户提交却不确定字段是否齐全、类型是否正确。与其手写一堆if去逐个检查Zod 让你声明一个 schema再调用一次.parse()就同时拿到运行时校验结果和静态类型推断。下面带你先 5 分钟跑通第一个例子再逐层拆开它的核心机制最后覆盖表单校验、API 边界校验等真实场景与常见坑。五分钟上手 ⏱️先装再跑。Zod 无外部依赖一行命令即可安装npm install zod最小可运行示例。定义一个对象 schema再喂给它一份数据import * as z from zod; const User z.object({ username: z.string(), xp: z.number(), }); const data User.parse({ username: billie, xp: 100 }); console.log(data); // { username: billie, xp: 100 }这段做了什么z.object把两个字段登记成一张校验清单.parse()对输入逐项核对全部通过才返回值任何一项不符就抛出ZodError。第一条成功结果。返回值不只是数据它还带着 TypeScript 推断出来的类型你无需再写interfacetype User z.infertypeof User; // { username: string; xp: number } const u: User { username: billie, xp: 100 };z.infer从 schema 反向提取类型schema 一改类型自动跟着变这就是声明一次、校验与类型两用。核心机制拆解结论一个 schema 既是运行时校验器也是类型定义。它把数据长什么样这件事写成了唯一的事实来源const User z.object({ username: z.string(), xp: z.number() }); User.parse({ username: a, xp: 1 }); // 运行时校验 type User z.infertypeof User; // 静态类型校验与类型出自同一份声明二者不会再出现接口和校验各写一遍的漂移。结论消费校验结果有两种方式——抛错或返回判别联合。parse失败即抛错safeParse则把结果装进一个带success标记的对象const res User.safeParse({ username: 42, xp: 100 }); if (!res.success) { res.error.issues; // 每个问题都带 expected、code、path、message } else { res.data; // { username: string; xp: number } }safeParse的结果是判别联合if (!res.success)就能让编译器自动收窄到错误分支适合表单这类需要逐字段提示的场景。结论输入和输出可以是两种类型。一旦用了.transform()进入的和出去的数据就不一样需要分别取const Age z.string().transform((s) Number(s)); type In z.inputtypeof Age; // string type Out z.outputtypeof Age; // number等价于 z.inferz.infer默认取输出类型要拿到进来时的类型用z.input。这解释了为什么 transform 后变量类型会跳变。结论跨字段规则靠 refine 补齐。单字段约束用链式方法字段之间互相牵制的逻辑用.refine()const Register z.object({ password: z.string().min(8), confirm: z.string(), }).refine((d) d.password d.confirm, { message: 两次密码不一致, path: [confirm], });refine收到的是整个对象可以任意断言path让报错精确挂到具体字段上方便前端定位。场景实战场景一注册表单的多字段校验。需求是把用户名、邮箱、年龄一次校验完失败时还要能告诉用户错在哪。import * as z from zod; const Signup z.object({ username: z.string().min(3).max(20).regex(/^[a-zA-Z0-9_]$/), email: z.string().email(), age: z.number().int().min(18), }); const res Signup.safeParse({ username: billie, email: bexample.com, age: 17, }); if (!res.success) { res.error.issues; // [{ path: [age], code: too_small, ... }] }关键点链式方法min/email/int就是校验器顺序即执行顺序。issues里每条都有path直接对应表单字段名渲染错误提示时零转换。用safeParse而非parse避免把预期内的失败变成异常流。场景二HTTP API 响应边界校验。微服务里第三方返回值不可信要在进入业务逻辑前挡一道但又不想为只是判断合不合法就构造完整错误。import * as z from zod; const ApiResp z.object({ success: z.boolean(), code: z.number().int().min(200).max(599), data: z.object({ id: z.string() }).optional(), }); function isApiResponse(v: unknown): boolean { return z.validate(ApiResp, v); // 只返回 boolean不构造错误 }关键点顶层z.validate(schema, value)只做判断比safeParse更轻适合高频边界。需要把data里的对象进一步收窄时再对它单独.safeParse拿结构化错误。边界处统一校验业务代码即可信任res.data的类型。场景三高频路径的 AOT 编译加速。列表、批量导入这类要解析上万条记录的接口逐节点派发的解析开销会被放大。import * as z from zod; const Row z.object({ id: z.string(), name: z.string(), age: z.number(), }); const fast z.compile(Row); // 预编译成扁平、无循环的校验器 fast.parse({ id: 1, name: a, age: 1 });关键点z.compile把逐键遍历展开成可直接执行的校验逻辑对象/数组这类容器收益最大仓库基准里大对象约 9 倍。合法输入走快速路径非法输入回退到常规解析器报错信息与原版一致。编译是最终形态才生效所以先写完整 schema 再compile见下方避坑。避坑指南 ⚠️现象只想判断合不合法却套了try/catch或safeParse。原因是parse会抛错、safeParse会构造完整ZodError判断合法时这些都做了多余工作。解法用顶层z.validate(schema, value)直接拿布尔值含异步 refine 时用z.validateAsync。现象对 schema 先.refine()再z.compile()性能没提升。原因是.refine()、.extend()这类派生方法返回的是未编译的新 schemacompile只作用于它传入的那一份。解法把编译放在最外层即z.compile(base.refine(...))而非z.compile(base).refine(...)。现象transform之后给变量赋值报类型不匹配。原因是输入类型和输出类型被分离了而z.infer取的是输出。解法表示进入 schema 前的数据用z.inputtypeof Schema表示出去后的用z.infer或z.output。现象含asyncrefine 的 schema 调.parse()结果不对或不生效。原因是异步校验需要被等待同步parse无法拿到 Promise 的结果。解法改用.parseAsync()/.safeParseAsync()并await它。周边联动 与 React Hook Form 集成。表单库提供了 Zod 的 resolverschema 直接当校验源错误字段自动对应到表单字段import { useForm } from react-hook-form; import { zodResolver } from hookform/resolvers/zod; import * as z from zod; const form z.object({ username: z.string().min(3) }); const { register, handleSubmit } useForm({ resolver: zodResolver(form), });与 JSON Schema 互转。需要把校验规则交给别的系统时Zod 内置了双向转换schema 到 JSON Schema 用toJSONSchema反向用fromJSONSchema实现见 json-schema 处理源码。收尾Zod 的核心价值在于把校验和类型收敛到同一份声明里parse给出类型安全的数据safeParse给出可渲染的错误compile在高频路径上省掉重复派发。理解了 schema 即事实来源这一点剩下都是 API 的取舍。想继续深挖可以从这几处入手基础用法解析、报错、类型推断基础用法文档AOT 编译的原理与限制编译说明经典 API 的核心实现classic 源码目录覆盖校验行为的完整用例测试用例目录【免费下载链接】zodTypeScript-first schema validation with static type inference项目地址: https://gitcode.com/GitHub_Trending/zo/zod创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考