news 2026/9/10 12:31:06

如何用 Zod 的 registry 集中管理 schema 的 description、examples 等元数据?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何用 Zod 的 registry 集中管理 schema 的 description、examples 等元数据?

如何用 Zod 的 registry 集中管理 schema 的 description、examples 等元数据?

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

当你的 Zod schema 不只是用来做运行时校验,还要参与文档生成、AI 结构化输出、表单校验或 JSON Schema 导出时,你经常需要给每个 schema 附带额外的说明信息:字段描述、示例值、标题、是否废弃等。Zod 4 用registry(注册表)来承担这件事:registry 是一组 schema 的集合,每个 schema 关联一份强类型的元数据。本文以仓库 packages/docs/content/metadata.mdx 的官方文档为主线,结合 packages/docs/content/json-schema.mdx 说明如何创建 registry、注册元数据、做类型约束,以及如何验证元数据确实被读到了。当前仓库中的 zod 版本为 4.5.4(见 packages/zod/package.json),registry 属于 Zod 4 的 API。

准备工作

安装 zod:

npm install zod

代码中通过import * as z from "zod"引入。

创建自定义 registry 并注册元数据

z.registry<T>()创建一个带元数据类型的 registry,T描述每个 schema 的元数据形状:

import * as z from "zod"; const myRegistry = z.registry<{ description: string }>();

然后对这个 registry 做注册、查询、删除:

const mySchema = z.string(); myRegistry.add(mySchema, { description: "A cool schema!" }); myRegistry.has(mySchema); // => true myRegistry.get(mySchema); // => { description: "A cool schema!" } myRegistry.remove(mySchema); myRegistry.clear(); // wipe registry

TypeScript 会强制每个 schema 的元数据符合 registry 声明的元数据类型:

myRegistry.add(mySchema, { description: "A cool schema!" }); // ✅ myRegistry.add(mySchema, { description: 123 }); // ❌

另一种写法是调用 schema 自己的.register()方法,把 schema 加入指定 registry。.register()与其他 Zod 方法不同:它不返回新 schema,而是返回原 schema.meta().describe()都会返回新实例)。因此可以在定义 schema 时“就地”写元数据:

const mySchema = z.string(); mySchema.register(myRegistry, { description: "A cool schema!" }); // => mySchema
const mySchema = z.object({ name: z.string().register(myRegistry, { description: "The user's name" }), age: z.number().register(myRegistry, { description: "The user's age" }), });

如果创建 registry 时没有指定元数据类型,它就是一个不带元数据的普通“集合”:

const myRegistry = z.registry(); myRegistry.add(z.string()); myRegistry.add(z.number());

用 z.globalRegistry 集中存放 description、examples 等公共元数据

除了自定义 registry,Zod 提供了一个全局 registryz.globalRegistry,可用于 JSON Schema 生成等场景。它接受的元数据形状是GlobalMeta接口:

export interface GlobalMeta { id?: string ; title?: string ; description?: string; deprecated?: boolean; [k: string]: unknown; }

由于examples等字段不在GlobalMeta的固定字段里(但被[k: string]: unknown索引签名放行),官方建议用declaration merging在全局扩充该接口。文档给出的约定是在项目根目录创建一个zod.d.ts文件(“常见约定”,而非强制要求):

declare module "zod" { interface GlobalMeta { // add new fields here examples?: unknown[]; } } // forces TypeScript to consider the file a module export {}

扩充之后就可以向z.globalRegistry注册完整的元数据:

import * as z from "zod"; const emailSchema = z.email().register(z.globalRegistry, { id: "email_address", title: "Email address", description: "Your email address", examples: ["first.last@example.com"] });

更省事的写法是.meta()方法,它直接注册到z.globalRegistry

const emailSchema = z.email().meta({ id: "email_address", title: "Email address", description: "Please enter a valid email address", });

.describe()则是只注册description字段的简写:

const emailSchema = z.email(); emailSchema.describe("An email address"); // equivalent to emailSchema.meta({ description: "An email address" });

文档说明.describe()仍然可用,但.meta()是推荐方式。Zod Mini 中没有.meta()的等价链式方法,文档给出的对应写法是z.email().check(z.meta({...}))/z.email().check(z.describe("...")),这里不展开。

让元数据引用 schema 的推断类型、约束 schema 类型

元数据里最有用的一类字段是“示例值”:它天然应该与 schema 的类型匹配。文档给出了两个进阶技巧。

引用推断类型:特殊符号z.$output指向 schema 的推断输出类型(即z.infer<typeof schema>),z.$input指向输入类型。用它定义元数据,examples就会按各 schema 的实际类型校验:

import * as z from "zod"; type MyMeta = { examples: z.$output[] }; const myRegistry = z.registry<MyMeta>(); myRegistry.add(z.string(), { examples: ["hello", "world"] }); myRegistry.add(z.number(), { examples: [1, 2, 3] });

约束 schema 类型:给z.registry()传第二个泛型,限制可以加入该 registry 的 schema 类型。下面的 registry 只接受字符串 schema:

import * as z from "zod"; const myRegistry = z.registry<{ description: string }, z.ZodString>(); myRegistry.add(z.string(), { description: "A number" }); // ✅ myRegistry.add(z.number(), { description: "A number" }); // ❌ // ^ 'ZodNumber' is not assignable to parameter of type 'ZodString'

验证元数据是否注册成功、是否生效

验证方式有三种,按强度递增:

1. 无参.meta()取回元数据。调用.meta()不带参数时会取回该 schema 的元数据:

emailSchema.meta(); // => { id: "email_address", title: "Email address", ... }

2. 用 registry 的get/has检查(如第一节示例所示,get返回注册的元数据对象,has返回boolean)。

3. 转换到 JSON Schema,确认元数据被复制进结果。在 packages/docs/content/json-schema.mdx 中,z.toJSONSchema()的第二个参数可以显式传入一个 registry(metadata参数),转换时会用它查找每个 schema 的元数据:

z.toJSONSchema(schema, { // ...params metadata: $ZodRegistry<Record<string, any>>; })

具体行为(文档示例输出):

// `.meta()` is a convenience method for registering a schema in `z.globalRegistry` const emailSchema = z.string().meta({ title: "Email address", description: "Your email address", }); z.toJSONSchema(emailSchema); // => { type: "string", title: "Email address", description: "Your email address", ... }

所有元数据字段都会被复制进 JSON Schema 结果,包括自定义字段:

const schema = z.string().meta({ whatever: 1234 }); z.toJSONSchema(schema); // => { type: "string", whatever: 1234 }

元数据优先于 Zod 自动生成的关键字,例如z.toJSONSchema(z.string().meta({ type: "number" }))的结果是{ type: "number" }。如果只想丢弃全部元数据,传一个空 registry:z.toJSONSchema(schema, { metadata: z.registry() })

限制与注意点

  • 元数据绑定在具体的 schema 实例上。Zod 的方法都是不可变的,永远返回新实例,衍生出来的 schema 不会自动“继承”到新实例的.meta()结果。文档示例:
const A = z.string().meta({ description: "A cool string" }); A.meta(); // => { description: "A cool string" } const B = A.refine(_ => true); B.meta(); // => undefined

也就是说,集中管理时要以“最终参与校验/导出的那个 schema 实例”为准注册元数据,中间衍生的实例需要时单独注册。(注意:自定义 registry 的get()在实现中会向schema._zod.parent继承父实例元数据且继承时剔除id,见 packages/zod/src/v4/core/registries.ts 中get方法;GlobalMeta本身没有这种继承说明,两者不要混用。)

  • id字段被特殊处理。metadata 文档提示:若多个 schema 以相同的id值注册(包括全局 registry),会抛出Error。在 JSON Schema 转换路径上有具体表现,仓库测试 packages/zod/src/v4/classic/tests/registries.test.ts 展示了:两个不同 schema 共用同一id并一起转换时,z.toJSONSchema抛出Duplicate schema id "duplicate-id" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.;而同一 schema 实例重复出现(同id)则不报错,会正常生成$defs。另外该测试还显示,add重复注册同一id本身不抛错(后注册的 schema 覆盖_idmap中的记录),错误在转换时暴露——即“重复id会报错”这一保证的触发点在 JSON Schema 转换阶段。

  • .register()返回原 schema,其余如.meta().describe()返回新实例。批量给字段注册元数据时用.register()可以保持 schema 引用不变,便于之后用同一实例做registry.get()/has()校验。

参考

  • 元数据与 registry 文档:packages/docs/content/metadata.mdx
  • JSON Schema 转换(metadata参数、targetunrepresentable等):packages/docs/content/json-schema.mdx
  • registry 实现($ZodRegistryglobalRegistryGlobalMeta):packages/zod/src/v4/core/registries.ts
  • registry 行为测试:packages/zod/src/v4/classic/tests/registries.test.ts

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

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

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

V 语言 JS 模块实战指南:在浏览器前端访问全局 JavaScript API

V 语言 JS 模块实战指南&#xff1a;在浏览器前端访问全局 JavaScript API 【免费下载链接】v Simple, fast, safe, compiled language for developing maintainable software. Compiles itself in <1s with zero library dependencies. Supports automatic C > V transl…

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

双馈风电机组Simulink建模:从电机本体到LVRT仿真全链路

简介&#xff1a;本资源是一套面向电气工程、新能源发电方向高校师生及风电系统仿真工程师的MATLAB双馈风力发电机组建模与分析实践资料&#xff0c;聚焦DFIG系统原理验证、控制策略实现与故障工况仿真。压缩包含35个文件&#xff0c;主体为16个Simulink模型&#xff08;.mdl&a…

作者头像 李华
网站建设 2026/9/10 12:26:18

SQL Server数据库自动清理双模式设计与实现

1. 项目概述&#xff1a;数据库自动清理的双模式设计 在数据处理领域&#xff0c;数据库膨胀是个永恒话题。我维护的某个生产系统曾因未及时清理历史数据&#xff0c;导致单表体积达到惊人的120GB&#xff0c;查询性能断崖式下跌。这个惨痛教训促使我设计了一套基于C#和SQL Ser…

作者头像 李华
网站建设 2026/9/10 12:25:07

图像配准偏移计算:互相关与归一化互相关方法详解

简介&#xff1a;面向图像处理初学者、科研人员与工程开发者&#xff0c;这份MATLAB示例包聚焦图像互相关、最大互相关与相关图像配准&#xff0c;通过自动计算两幅图像在所有位移下的相似度&#xff0c;找出互相关函数的峰值位置&#xff0c;从而得到x/y方向的配准偏移量&…

作者头像 李华