尧图精选

上手Zod v4的schema验证:一份声明搞定unknown输入与类型推断

🕒 发布时间:2026/8/31 8:10:23 📁 来源:尧图网络
上手Zod v4的schema验证一份声明搞定unknown输入与类型推断【免费下载链接】zodTypeScript-first schema validation with static type inference项目地址: https://gitcode.com/GitHub_Trending/zo/zodAPI 把 number 字段返回成字符串 100 时你写的 interface 救不了你——接口只在编译期生效运行时数据照样裸奔。Zod 用一份 schema 解决这件事声明一次数据结构验证、错误定位、静态类型推断一次到位核心包只有 2kbgzip。 先跑起来安装 Zod 并完成第一次 parse痛点一句话每次收到外部数据请求体、localStorage、配置文件都要手写一堆typeof x number检查。Zod 的思路是把这些检查收敛成一份声明验证由库来跑。先装包它是零外部依赖的npm install zod当前版本是 4.5.4Node 和现代浏览器都能直接用。下面这段演示最基础的用法声明一个对象 schema然后用.parse()验证一份数据import * as z from zod; const Player z.object({ username: z.string(), xp: z.number(), }); const raw { username: billie, xp: 100 }; // 来自外部的 unknown 数据 const data Player.parse(raw); // 不合规会直接抛 ZodError console.log(data.username); // billie且类型是 string运行后parse成功会返回输入的强类型深拷贝只要有任何字段不合 schema它立即抛出一个ZodError中断流程。注意parse是抛异常风格的 API适合不合法就直接挂掉的场景。 验证失败时怎么办用 safeParse 定位到具体字段如果你的代码不能因为一条脏数据就整体崩溃比如要给用户回显表单错误就换.safeParse()const result Player.safeParse({ username: 42, xp: 100 }); if (!result.success) { console.log(result.error.issues); // [{ code: invalid_type, path: [username], message: ... }, // { code: invalid_type, path: [xp], message: ... }] } else { const data result.data; // 类型保证是 { username: string; xp: number } }结果是一个判别联合success为 true 拿data为 false 拿error.issues每个 issue 都带path错在哪个字段和message直接可以映射到表单红字上。这里有个常见的版本坑v4 的报错文案定制是直接把字符串传给 schema 的第一个参数v3 时代的required_error/invalid_type_error参数不再适用字符串校验也推荐用独立的z.email()而不是 v3 的z.string().email()写法const Signup z.object({ email: z.email(请输入有效的邮箱), // 定制文案 age: z.number().int(年龄必须是整数), }); Signup.safeParse({ email: abc, age: 18 }).error?.issues; // message 都会变成你写的中文文案 别再单写 interface 了z.infer 让类型跟 schema 走痛点同一份数据结构你往往维护了两份真相——一份运行时校验一份 TypeScript 类型改字段时容易漏一处。Zod 的类型是从 schema 推导出来的只有一份真相// schema 不变类型自动推导 type Player z.infertypeof Player; // { username: string; xp: number } function render(p: Player) { return p.username; // 编辑器直接知道类型无需手写 interface }当 schema 带.transform()或 codec 这类输入类型 ≠ 输出类型的构造时还能分别取z.input和z.output对应数据进和出的两个方向。想对照完整 API可以翻 packages/docs/content/basics.mdx。 一份 schema 前后端共用z.codec 双向转换痛点服务端存 Date网络上传 ISO 字符串客户端拿到后再转回来——两头各写一遍转换函数方向一对不上就出 bug。z.codec()4.1 引入把两个方向的 schema 两个方向的转换打包成一个可共用的对象下面这段演示一个典型的 ISO 字符串与 Date 互转 codecconst stringToDate z.codec( z.iso.datetime(), // 输入方向ISO 时间字符串 z.date(), // 输出方向Date 对象 { decode: (iso) new Date(iso), // 字符串 - Date encode: (d) d.toISOString(), // Date - 字符串 } ); stringToDate.decode(2024-01-15T10:30:00.000Z); // Date stringToDate.encode(new Date(2024-01-15T10:30:00.000Z)); // ISO 字符串客户端用.decode()把网络数据转成富类型服务端返回前用.encode()转回 JSON 友好格式转换规则只写一次、天然不会跑偏。 业务里绕不开的两个结构判别联合与递归 schema真实的业务数据很少是平铺对象要么是多分支联合要么是无限嵌套。这两个 Zod 都有原生构造// 判别联合用 kind 字段区分分支类型推导也分得开 const Shape z.discriminatedUnion(kind, [ z.object({ kind: z.literal(circle), radius: z.number() }), z.object({ kind: z.literal(square), side: z.number() }), ]); // 递归结构用 z.lazy 让 schema 指向自己 const TreeNode z.object({ value: z.string(), children: z.array(z.lazy(() TreeNode)).optional(), });判别联合在运行时按kind精确分发TreeNode能验证任意深度的树形数据z.lazy是解决schema 定义时引用自己还没定义完这个循环问题的标准手段。⚡ 热点路径嫌慢z.compile 预编译出快路径痛点高频场景比如每条请求都过一遍 schema里常规 parse 的逐节点分发是有成本的。z.compile()会对 schema 做一次 AOT 编译生成带编译快路径的克隆import * as z from zod; const Player z.object({ username: z.string(), xp: z.number() }); const Fast z.compile(Player); Fast.parse({ username: billie, xp: 100 }); // 合法输入走编译后的快路径官方 55 个 schema 的基准测试里中位数提速 2.4 倍schema 负载越重收益越大——大对象数组约 9 倍、20 字段对象约 9 倍而裸z.string()这种几乎没东西可省的构造则没有收益。合法输入走快路径非法输入自动回退常规解析器所以错误报告与普通 parse 完全一致另外只要只需要判断合不合法顶层的z.validate()比.safeParse().success最高快 16 倍。schema 类本身是怎么搭起来的core 与 classic 层的继承关系可以参考这张结构图和 packages/zod/src/v4/classic/ 源码下一步可以做什么在你项目里找一个现有的interface 手写校验组合把它替换成一个 Zod schema用z.infer统一类型来源打开 wiki/compile.md 和 packages/docs/content/compile.mdx看z.compile在异步 refinement 等场景下的回退细节如果只想要轻量版本试一下import { z } from zod/miniAPI 风格略有不同但同样支持 codec 和 compile【免费下载链接】zodTypeScript-first schema validation with static type inference项目地址: https://gitcode.com/GitHub_Trending/zo/zod创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →