💎 雨云 RainYun - 企业级云计算服务提供商
Zod logo

给库作者的指南

编辑此页面

本页面主要面向正在基于 Zod 构建工具的库作者

如果您是库作者,且认为页面应包含额外指导,请提交 issue!

我需要依赖 Zod 吗?

Zod 3 在功能上已结束生命周期。它仍会接收安全修复和明确的错误修复,但 [email protected] 将不再加入新功能。对于任何新库——或现有库的任何新主版本——请仅面向 Zod 4。有关双重支持模式(旨在帮助扩展现有库的维护者),请参阅如何在支持 Zod 4 的同时支持 Zod 3?

我需要依赖 Zod 吗?

如果你在开发一个接受用户自定义 schema 作为黑盒验证的库,可能不必专门集成 Zod。可以考虑使用 Standard Schema。这是 TypeScript 生态中大多数主流验证库实现的共享接口(参考完整列表),Zod 也在其中。

该规范非常适合接受用户定义 schema 并将其视作“黑盒”验证器。任何符合规范的库都能推断输入/输出类型、验证输入并提供标准化错误。

如果你需要 Zod 独有的功能,请继续阅读。

如何配置 peer 依赖?

任何基于 Zod 的库都应在 "peerDependencies" 中包含 "zod",让用户“自带 Zod”。

// package.json
{
  // ...
  "peerDependencies": {
    "zod": "^4.0.0"
  }
}

在开发期间,你需要满足自身的 peer 依赖要求,因此也要将 "zod" 添加到 "devDependencies" 中。

// package.json
{
  "peerDependencies": {
    "zod": "^4.0.0"
  },
  "devDependencies": {
    "zod": "^4.0.0"
  }
}

如果你是在扩展现有库,并希望继续支持 Zod 3 用户,请参阅如何同时支持 Zod 3 和 Zod 4?以了解更宽泛的 peer 依赖范围。

我应该从哪些子路径导入?

"zod/v4/core" 子路径导入 Zod 4 核心包:

import * as z4 from "zod/v4/core";

可以将此子路径视为指向 Zod 4 的“永久链接”。即使在 zod 包未来发布主要版本后,它也将永久保留。另一个永久链接子路径是 "zod/v3",仅当你同时支持 Zod 3时才需要使用它。

通常不应从其他路径导入。Zod Core 库是一个共享库,为 Zod 4 Classic 和 Zod 4 Mini 提供底层支持。通常来说,实现特定于其中某一个版本的功能并不是一个好主意。不要从以下子路径导入:

  • "zod" — ❌ 在 3.x 版本中,此路径导出 Zod 3;在 4.x 版本中,此路径导出 Zod 4。请改用永久链接。
  • "zod/v4""zod/v4/mini" — ❌ 这些子路径分别是 Zod 4 Classic 和 Mini 的所在位置。如果你希望你的库同时适用于 Zod 和 Zod Mini,就应该基于 "zod/v4/core" 中定义的基类进行构建。如果引用 "zod/v4" 模块中的类,你的库将无法与 Zod Mini 一起使用,反之亦然。强烈不建议这样做。请改用 "zod/v4/core",它导出了由 Zod Classic 和 Zod Mini 扩展的带 $ 前缀的子类。Classic 和 Mini 子类的内部实现完全相同;它们的唯一区别在于实现了哪些辅助方法。

如需全面了解这种版本控制方式,请参阅《Zod 4 中的版本控制》

如何同时支持 Zod 3 和 Zod 4?

本节面向现有库的维护者,这些库中有 Zod 3 用户。对于新库(或现有库的新主版本),仅支持 ^4.0.0 —— Zod 3 实际上已经结束生命周期,不会再获得新功能。

如果你维护的库中有现有的 Zod 3 用户,可以在不放弃这些用户的情况下扩展支持 Zod 4。将对等依赖范围扩大到同时涵盖两个版本范围 —— "zod/v4" 子路径从 3.25.0 开始可用:

// package.json
{
  // ...
  "peerDependencies": {
    "zod": "^3.25.0 || ^4.0.0"
  }
}

这不需要发布库的新主版本。更新对等依赖会要求用户执行 npm upgrade zod,但 [email protected][email protected] 之间没有破坏性变更(实际上完全没有代码变更),因此添加 Zod 4 支持可以在次版本中发布。如果你的库本来就要发布主版本,那么发布一个移除 Zod 3 支持、并将对等依赖范围缩小到 ^4.0.0 的主版本会是更简洁的选择。

v3.25.0 开始,zod 包在各自的子路径中同时包含 Zod 3 和 Zod 4 的副本,因此你可以并列导入两者:

import * as z3 from "zod/v3";
import * as z4 from "zod/v4/core";
 
type Schema = z3.ZodTypeAny | z4.$ZodType;
 
function acceptUserSchema(schema: z3.ZodTypeAny | z4.$ZodType) {
  // ...
}

要运行时区分 Zod 3 和 Zod 4 schema,可检查 "_zod" 属性。只有 Zod 4 schema 拥有该属性。

import type * as z3 from "zod/v3";
import type * as z4 from "zod/v4/core";
 
declare const schema: z3.ZodTypeAny | z4.$ZodType;
 
if ("_zod" in schema) {
  schema._zod.def; // Zod 4 schema
} else {
  schema._def; // Zod 3 schema
}

如何同时支持 Zod 和 Zod Mini?

你的库代码应仅从 "zod/v4/core" 导入。此子包定义了 Zod 和 Zod Mini 共享的接口、类和工具。只要遵循这一规则,Zod 和 Zod Mini 都会自动正常工作。

// 库代码
import * as z4 from "zod/v4/core";
 
export function acceptObjectSchema<T extends z4.$ZodObject>(schema: T){
  // 解析数据
  z4.parse(schema, { /* 某些数据 */});
  // 查看内部结构
  schema._zod.def.shape;
}

基于共享基接口开发,可同时兼容两个子包。此函数可接受 Zod 和 Zod Mini 的 schema。

// 用户代码
import { acceptObjectSchema } from "your-library";
 
// Zod 4
import * as z from "zod";
acceptObjectSchema(z.object({ name: z.string() }));
 
// Zod 4 Mini
import * as zm from "zod/mini";
acceptObjectSchema(zm.object({ name: zm.string() }))

更多关于核心子库的信息,请访问 Zod Core 页面。

如何接受用户定义的 schema?

接受用户定义的 schema 是基于 Zod 构建库的基本操作,下面是最佳实践。

初学时,可能想写一个函数接收 Zod schema,如:

import * as z4 from "zod/v4/core";
 
function inferSchema<T>(schema: z4.$ZodType<T>) {
  return schema;
}

这种写法不正确,会限制 TypeScript 正确推断参数类型。无论传入什么,schema 类型都是 $ZodType 实例。

inferSchema(z.string());
// => $ZodType<string>

这样会丢失类型信息,尤其是具体子类(如 ZodString)。这意味着无法调用 .min() 等字符串专属方法。应让泛型继承核心 Zod schema 接口:

function inferSchema<T extends z4.$ZodType>(schema: T) {
  return schema;
}
 
inferSchema(z.string());
// => ZodString ✅

要限制输入 schema 为特定子类:

import * as z4 from "zod/v4/core";
 
// 只接受对象 schema
function inferSchema<T extends z4.$ZodObject>(schema: T) {
  return schema;
}

限制输入 schema 的推断输出类型:

import * as z4 from "zod/v4/core";
 
// 只接受字符串 schema
function inferSchema<T extends z4.$ZodType<string>>(schema: T) {
  return schema;
}
 
inferSchema(z.string()); // ✅ 
 
inferSchema(z.number()); 
// ❌ 不兼容:
// // 类型 '_zod.output' 不匹配,number 不能赋值给 string

要用 schema 解析数据,使用顶层的 z4.parse/z4.safeParse/z4.parseAsync/z4.safeParseAsync 函数。z4.$ZodType 子类自身无解析方法。解析通常由 Zod 和 Zod Mini 提供,Zod Core 无此功能。

function parseData<T extends z4.$ZodType>(data: unknown, schema: T): z4.output<T> {
  return z.parse(schema, data);
}
 
parseData("sup", z.string());
// => string

On this page