Zod logo

面向库作者

本页面主要供正在基于 Zod 构建工具的库作者使用。

🌐 This page is primarily intended for consumption by library authors who are building tooling on top of Zod.

如果你是库的作者,并且认为此页面应该包含一些额外的指导,请提出问题!

Zod 3 在功能上已经到生命周期末期。它仍然会收到安全修复和明确的错误修复,但不会再有新的功能添加到 zod@3.x。对于任何新的库 —— 或者现有库的任何新的主要版本 —— 仅针对 Zod 4。有关双重支持模式的更多信息,请参见 如何在 Zod 4 的同时支持 Zod 3?,该模式适用于扩展现有库的维护者。

我需要依赖 Zod 吗?

🌐 Do I need to depend on Zod?

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

🌐 First things first, make sure you need to depend on Zod at all.

如果你正在构建一个接受用户定义的模式以执行黑箱验证的库,你可能不需要特别与 Zod 集成。相反,可以查看 Standard Schema。它是大多数流行 TypeScript 验证库实现的一个共享接口(参见 完整列表),包括 Zod。

🌐 If you're building a library that accepts user-defined schemas to perform black-box validation, you may not need to integrate with Zod specifically. Instead look into Standard Schema. It's a shared interface implemented by most popular validation libraries in the TypeScript ecosystem (see the full list), including Zod.

如果你接受用户定义的模式并将它们视为“黑箱”验证器,这个规范效果很好。对于任何符合规范的库,你都可以提取推断的输入/输出类型,验证输入,并获得标准化的错误信息。

🌐 This spec works great if you accept user-defined schemas and treat them like "black box" validators. Given any compliant library, you can extract inferred input/output types, validate inputs, and get back a standardized error.

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

🌐 If you need Zod specific functionality, read on.

如何配置对等依赖?

🌐 How to configure peer dependencies?

任何建立在 Zod 之上的库都应该在 "peerDependencies" 中包含 "zod"。这让你的用户可以“自带 Zod”。

🌐 Any library built on top of Zod should include "zod" in "peerDependencies". This lets your users "bring their own Zod".

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

在开发过程中,你需要满足你自己的同行依赖要求,所以也将 "zod" 添加到你的 "devDependencies" 中。

🌐 During development, you need to meet your own peer dependency requirement, so add "zod" to your "devDependencies" as well.

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

如果你正在扩展现有库并希望继续支持 Zod 3 用户,请参阅 如何在 Zod 4 的同时支持 Zod 3? 以获取更广泛的对等依赖范围。

🌐 If you're extending an existing library and wish to keep supporting Zod 3 users, see How to support Zod 3 alongside Zod 4? for the wider peer dependency range.

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

🌐 Which subpaths should I import from?

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

🌐 Import the Zod 4 core package from the "zod/v4/core" subpath:

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

把这个子路径看作是 Zod 4 的“永久链接”。它将永远可用,即使在未来的 zod 主要版本中也是如此。唯一的其他永久链接子路径是 "zod/v3",只有在你也支持 Zod 3 时才需要它。

🌐 Think of this subpath as a "permalink" to Zod 4. It will remain available forever, even across future major versions of the zod package. The only other permalink subpath is "zod/v3", which you only need if you're also supporting Zod 3.

你通常不应该从其他路径导入。Zod Core 库是一个共享库,支撑着 Zod 4 Classic 和 Zod 4 Mini。实现任何特定于某一版本的功能通常不是一个好主意。不要从这些子路径导入:

🌐 You generally shouldn't be importing from any other paths. The Zod Core library is a shared library that undergirds both Zod 4 Classic and Zod 4 Mini. It's generally a bad idea to implement any functionality that is specific to one or the other. Do not import from these subpaths:

  • "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 中的版本控制 说明。

🌐 For full context on this versioning approach, see the Versioning in Zod 4 writeup.

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

🌐 How to support Zod 3 alongside Zod 4?

本节面向使用 Zod 3 的现有库维护者。对于新库(或现有库的新主要版本),仅支持 ^4.0.0 — Zod 3 功能上已接近生命周期结束,不会收到新功能。

如果你维护一个已有 Zod 3 用户的库,你可以在不抛弃他们的情况下扩展它以支持 Zod 4。将你的同级依赖范围扩大到覆盖两个版本区间——"zod/v4" 子路径从 3.25.0 开始可用:

🌐 If you maintain a library with existing Zod 3 users, you can extend it to cover Zod 4 without dropping them. Widen your peer dependency to span both ranges — the "zod/v4" subpath is available starting in 3.25.0:

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

这不需要你的库发布新的大版本。提升同行依赖会要求你的用户 npm upgrade zod,但在 zod@3.24zod@3.25 之间没有破坏性更改(实际上,根本没有任何代码更改),所以添加对 Zod 4 的支持可以在小版本中实现。如果你的库本来就需要发布大版本,那么发布一个放弃 Zod 3 并将同行依赖范围缩小到 ^4.0.0 的大版本是更干净的选择。

🌐 This doesn't require a new major version of your library. Bumping the peer dependency requires your users to npm upgrade zod, but there were no breaking changes (in fact, no code changes at all) between zod@3.24 and zod@3.25, so adding Zod 4 support can land in a minor. If your library is due for a major anyway, cutting one that drops Zod 3 and narrows the peer range to ^4.0.0 is the cleaner option.

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

🌐 Since v3.25.0 the zod package contains copies of both Zod 3 and Zod 4 at their respective subpaths, so you can import both side by side:

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 上定义。

🌐 To differentiate between Zod 3 and Zod 4 schemas at runtime, check for the "_zod" property. This property is only defined on Zod 4 schemas.

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?

🌐 How to support Zod and Zod Mini simultaneously?

你的库代码应该只从 "zod/v4/core" 导入。这个子包定义了 Zod 和 Zod Mini 之间共享的接口、类和工具。只要你遵守这个规则,Zod 和 Zod Mini 都会自动工作。

🌐 Your library code should only import from "zod/v4/core". This sub-package defines the interfaces, classes, and utilities that are shared between Zod and Zod Mini. As long as you follow this rule, both Zod and Zod Mini will work automatically.

// library code
import * as z4 from "zod/v4/core";
 
export function acceptObjectSchema<T extends z4.$ZodObject>(schema: T){
  // parse data
  z4.parse(schema, { /* somedata */});
  // inspect internals
  schema._zod.def.shape;
}

通过针对共享的基础接口进行构建,你可以可靠地同时支持两个子包。此函数可以接受 Zod 和 Zod Mini 架构。

🌐 By building against the shared base interfaces, you can reliably support both sub-packages simultaneously. This function can accept both Zod and Zod Mini schemas.

// user code
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 页面。

🌐 Refer to the Zod Core page for more information on the contents of the core sub-library.

如何接受用户定义的模式?

🌐 How to accept user-defined schemas?

接受用户定义的模式是任何基于 Zod 构建的库的一个基本操作。本节概述了执行此操作的最佳实践。

🌐 Accepting user-defined schemas is the a fundamental operation for any library built on Zod. This section outlines the best practices for doing so.

刚开始时,可​​能很容易编写一个接受 Zod 模式的函数,如下所示:

🌐 When starting out, it may be tempting to write a function that accepts a Zod schema like this:

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

这种方法是不正确的,并且限制了 TypeScript 正确推断参数的能力。无论你传入什么,schema 的类型都会是 $ZodType 的一个实例。

🌐 This approach is incorrect, and limits TypeScript's ability to properly infer the argument. No matter what you pass in, the type of schema will be an instance of $ZodType.

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

这种方法会丢失类型信息,即输入实际上属于哪个子类(在此例中为 ZodString)。这意味着你无法在 inferSchema 的结果上调用任何字符串特定的方法,比如 .min()。相反,你的泛型参数应该扩展核心 Zod 模式接口:

🌐 This approach loses type information, namely which subclass the input actually is (in this case, ZodString). That means you can't call any string-specific methods like .min() on the result of inferSchema. Instead, your generic parameter should extend the core Zod schema interface:

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

要将输入模式限制为特定子类:

🌐 To constrain the input schema to a specific subclass:

 
import * as z4 from "zod/v4/core";
 
// only accepts object schemas
function inferSchema<T extends z4.$ZodObject>(schema: T) {
  return schema;
}

要限制输入模式的推断输出类型:

🌐 To constrain the inferred output type of the input schema:

 
import * as z4 from "zod/v4/core";
 
// only accepts string schemas
function inferSchema<T extends z4.$ZodType<string>>(schema: T) {
  return schema;
}
 
inferSchema(z.string()); // ✅ 
 
inferSchema(z.number()); 
// ❌ The types of '_zod.output' are incompatible between these types. 
// // Type 'number' is not assignable to type 'string'

要使用该模式解析数据,请使用顶层的 z4.parse/z4.safeParse/z4.parseAsync/z4.safeParseAsync 函数。z4.$ZodType 子类没有任何方法。常用的解析方法由 Zod 和 Zod Mini 实现,但在 Zod Core 中不可用。

🌐 To parse data with the schema, use the top-level z4.parse/z4.safeParse/z4.parseAsync/z4.safeParseAsync functions. The z4.$ZodType subclass has no methods on it. The usual parsing methods are implemented by Zod and Zod Mini, but are not available in 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