
如何用 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.jsonregistry 属于 Zod 4 的 API。准备工作安装 zodnpm install zod代码中通过import * as z from zod引入。创建自定义 registry 并注册元数据用z.registryT()创建一个带元数据类型的 registryT描述每个 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 registryTypeScript 会强制每个 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! }); // mySchemaconst mySchema z.object({ name: z.string().register(myRegistry, { description: The users name }), age: z.number().register(myRegistry, { description: The users age }), });如果创建 registry 时没有指定元数据类型它就是一个不带元数据的普通“集合”const myRegistry z.registry(); myRegistry.add(z.string()); myRegistry.add(z.number());用 z.globalRegistry 集中存放 description、examples 等公共元数据除了自定义 registryZod 提供了一个全局 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.lastexample.com] });更省事的写法是.meta()方法它直接注册到z.globalRegistryconst 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.infertypeof schemaz.$input指向输入类型。用它定义元数据examples就会按各 schema 的实际类型校验import * as z from zod; type MyMeta { examples: z.$output[] }; const myRegistry z.registryMyMeta(); myRegistry.add(z.string(), { examples: [hello, world] }); myRegistry.add(z.number(), { examples: [1, 2, 3] });约束 schema 类型给z.registry()传第二个泛型限制可以加入该 registry 的 schema 类型。下面的 registry 只接受字符串 schemaimport * 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()的第二个参数可以显式传入一个 registrymetadata参数转换时会用它查找每个 schema 的元数据z.toJSONSchema(schema, { // ...params metadata: $ZodRegistryRecordstring, 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 }。如果只想丢弃全部元数据传一个空 registryz.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.mdxJSON Schema 转换metadata参数、target、unrepresentable等packages/docs/content/json-schema.mdxregistry 实现$ZodRegistry、globalRegistry、GlobalMetapackages/zod/src/v4/core/registries.tsregistry 行为测试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),仅供参考