拓冰建站拓冰建站
首页 / 资讯中心 / 正文

如何在 Zod 中定义自引用的递归对象 schema?

如何在 Zod 中定义自引用的递归对象 schema【免费下载链接】zodTypeScript-first schema validation with static type inference项目地址: https://gitcode.com/GitHub_Trending/zo/zod在 Zod v4 中如果一个对象的字段引用对象自身比如分类树、评论的楼中楼、链表节点就需要定义递归 schema。Zod 4 提供了基于 getter 的写法在z.object()的某个键上使用 getter 返回引用自身 schema 的表达式JavaScript 会在运行时解析这个循环引用TypeScript 则能直接推断出递归类型——不需要 Zod 3 时代的类型断言。本文基于仓库内文档 packages/docs/content/api.mdx 的 Recursive objects 章节和 packages/docs/content/v4/index.mdx 说明完整操作路径并给出可对照的验证方式。准备环境按 packages/zod/README.md 安装并使用 Zod v4npm install zodimport * as z from zod;文档对 Node 版本等运行环境没有额外前置要求递归 schema 本身不依赖任何编译开关parse()即可直接使用。用 getter 定义自引用对象文档给出的自引用写法是把递归字段声明为 getterconst Category z.object({ name: z.string(), get subcategories() { return z.array(Category); } }); type Category z.infertypeof Category; // { name: string; subcategories: Category[] }关键点有两个get subcategories()是 ES 的对象 getter而不是普通的函数属性。文档明确说这是为了让 JavaScript 在运行时解析循环 schemacyclical schemaz.infertypeof Category会把结果推断为递归类型{ name: string; subcategories: Category[] }即 getter 机制让 TypeScript 直接支持递归类型推断无需断言。注意 getter 键的推断结果会体现在类型上getter 定义的键在 shape 中不携带readonly修饰shape类型为{ name: z.ZodString; subcategories: z.ZodArraytypeof Category }见测试 packages/zod/src/v4/classic/tests/recursive-types.test.ts 的 pick and omit with getter 用例。验证递归解析构造循环输入并检查输出图文档指出循环输入cyclical inputs在标准 Zod 中开箱即用。文档示例Zod 标签页const input: any { name: root, subcategories: [] }; input.subcategories.push(input); const result Category.parse(input); result.subcategories[0] result; // true // the output graph mirrors the input graph result.subcategories[0].subcategories[0] result; // true这里的判断标准是解析不抛错且输出对象保留引用身份identity——输出图镜像输入图subcategories[0]就是解析结果本身。文档示例中的// true是该示例输入下应当得到的判断结果可以照抄执行来验证你的 schema 是否建对了。更严格的验证可参考仓库测试 packages/zod/src/v4/classic/tests/cyclic-data.test.ts其中还覆盖了几类值得了解的解析行为同一输入节点的多个引用共享同一个输出节点而两次独立的parse()调用互不影响循环输入不会被修改甚至Object.freeze()冻结的输入也能解析如果某个节点值不合法例如id不是 numbersafeParse只报告一个 issue且 path 指向它自身如[id]循环通过.transform()闭合时会被拒绝抛出/reference cycle/错误——变换会新建对象无法镜像引用图这是明确的边界。可选分支Zod Mini 需要显式注册 memoizer如果你用的是轻量版 Zod Mini文档说明出于包体积考虑它默认不内置 memoizer需要在定义 schema 之前显式注册文档示例// Zod Mini requires a memoizer, registered before schemas are defined z.config({ memoizer: z.memoizer() }); const input: any { name: root, subcategories: [] }; input.subcategories.push(input); const result Category.parse(input); result.subcategories[0] result; // true标准zod导入不需要这一步。互递归mutual recursion两个对象互相引用时同样用 getter文档示例const User z.object({ email: z.email(), get posts() { return z.array(Post); } }); const Post z.object({ title: z.string(), get author() { return User; } });getter 允许引用尚未完成初始化的另一个const因为 getter 只在被访问时解析时执行此时Post已定义。文档同时说明递归 schema 依然是普通的ZodObject实例.pick()、.omit()、.required()、.partial()、.extend()等对象 API 照常可用Post.pick({ title: true }); Post.partial(); Post.extend({ publishDate: z.date() });测试用例 recursive-types.test.ts 还展示了pick/omit对递归键的实际效果Category.pick({ name: true })之后含subcategories键的输入会parse失败说明派生 schema 正确地丢掉了递归分支。遇到 TS7023 循环类型错误怎么办文档提示由于 TypeScript 的限制递归类型推断只在特定场景下工作。较复杂的写法可能触发循环类型错误文档给出的典型报错ts(7023)const Activity z.object({ name: z.string(), get subactivities() { // ^ ❌ subactivities implicitly has return type any because it does not // have a return type annotation and is referenced directly or indirectly // in one of its return expressions.ts(7023) return z.nullable(z.array(Activity)); }, });解决办法是给出问题的 getter 加上返回类型注解const Activity z.object({ name: z.string(), get subactivities(): z.ZodNullablez.ZodArraytypeof Activity { return z.nullable(z.array(Activity)); }, });测试中另一个已验证的写法是 getter 直接使用方法链如return z.array(Category).optional().nullable()对应的推断结果见 recursive-types.test.ts 断言的subcategories?: _Category[] | undefined | null。边界与限制循环输入依赖 memoizer 机制标准 Zod 默认配置即包含 memoizerZod Mini 需按上文注册。循环通过.transform()闭合时解析会抛/reference cycle/错误见 cyclic-data.test.ts需要变换的场景应避免让 transform 处在环路上。递归类型推断受 TypeScript 限制遇到 7023 类错误时优先给 getter 加类型注解而不是换写法。完成以上步骤后可用文档的示例输入直接跑一遍parse()并断言result.subcategories[0] result即可确认递归 schema 的定义与解析都符合预期。【免费下载链接】zodTypeScript-first schema validation with static type inference项目地址: https://gitcode.com/GitHub_Trending/zo/zod创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门