💎 Zod 4 现已稳定发布! 阅读公告。
Zod logo

给库作者的指南

Edit this page

更新 — 2025 年 7 月 10 日

Zod 4.0.0 已在 npm 发布。此版本完成了下面所述的增量发布流程。要添加支持,请将你的 peer 依赖升级为包含 zod@^4.0.0

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

如果你已经根据下文中描述的最佳实践实现了 Zod 4 支持(例如使用 "zod/v4/core" 的子路径),则无需其他代码更改。通常这不需要发布你库的新主版本。

本页主要面向 库作者,他们基于 Zod 构建工具链。

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

我需要依赖 Zod 吗?

首先,确保你确实需要依赖 Zod。

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

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

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

如何配置 peer 依赖?

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

// package.json
{
  // ...
  "peerDependencies": {
    "zod": "^3.25.0 || ^4.0.0" // 3.25.0 添加了 "zod/v4" 子路径
  }
}

开发时,需要满足自己的 peer 依赖要求,所以也应将 "zod" 加入 "devDependencies"

// package.json
{
  "peerDependencies": {
    "zod": "^3.25.0 || ^4.0.0"
  },
  "devDependencies": {
    // 通常,应以最新版本 Zod 进行开发
    "zod": "^3.25.0 || ^4.0.0"
  }
}

如何支持 Zod 4?

要支持 Zod 4,将 "zod" 的 peer 依赖最低版本更新为 ^3.25.0 || ^4.0.0

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

v3.25.0 开始,Zod 4 的核心包提供了 "zod/v4/core" 子路径。完整版本策略请参阅 Zod 4 的版本控制

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

仅从这些子路径导入,可视作对应 Zod 版本的“永久链接”,且始终可用。

  • "zod/v3" 用于 Zod 3 ✅
  • "zod/v4/core" 用于 Zod 4 核心包 ✅

通常不应从其他路径导入。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,不推荐)。

你需要将 peer 依赖提升到 ^3.25.0,用户执行 npm upgrade zod。不过从 zod@3.24zod@3.25,Zod 3 没有任何破坏性变更,也不需修改代码。由于用户需升级并改代码,我不认为这是破坏性变更,不建议发布新主版本。

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

v3.25.0 起,包内包含 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 共享的接口、类和工具。

// 库代码
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>(schema: z4.$ZodObject) {
  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