💎 Zod 4 is now stable!  Read the announcement.
Zod logo

版本控制

更新 — 2025 年 7 月 8 日

[email protected] 已发布到 npm。包根目录("zod")现在导出 Zod 4。所有其他子路径均未更改,并将永远可用。

要升级到 Zod 4:

npm install zod@^4.0.0

如果您正在使用 Zod 4,您现有的导入("zod/v4""zod/v4-mini")将永远继续工作。但是,升级后,您可以 选择性地 重写您的导入如下:

之前之后
Zod 4"zod/v4""zod"
Zod 4 Mini"zod/v4-mini""zod/mini"
Zod 3"zod""zod/v3"

库作者 — 如果您已根据 库作者 指南中概述的最佳实践实现了 Zod 4 支持,请更新您的对等依赖(peer dependency)以包含 zod@^4.0.0

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

应该没有其他必要的代码更改。 最新的 3.25.x 版本和 4.0.0 之间没有进行代码更改。这不需要重大的版本变更。

关于子路径版本控制的一些说明

归根结底,子路径版本控制方案是一种必要的手段,目的是迫使生态系统以非破坏性的方式进行升级。如果我一开始就发布 [email protected],大多数库都会天真地更新它们的对等依赖,从而在整个生态系统中引发“版本更新雪崩”。

就目前情况而言,Zod 4 在整个生态系统中得到了 广泛支持。没有哪个迁移过程是完全无痛的,但我担心的“版本雪崩”似乎并没有发生。总的来说,各个库都能够同时支持 Zod 3 和 Zod 4:Hono、LangChain、React Hook Form 等等。几位生态系统维护者专门联系我,表示逐步添加对 Zod 4 的支持是多么方便(这通常需要重大的版本变更)。长话短说:这种方法效果很好!很少有其他库受到与 Zod 相同的限制,但我强烈鼓励其他拥有大型关联生态系统的库考虑类似的方法。

Zod 4 中的版本控制

这是关于 Zod 4 版本控制方法的说明,目的是让用户和 Zod 的关联库生态系统更容易迁移到 Zod 4。

总体方法:

  • Zod 4 最初不会以 [email protected] 发布在 npm 上。相反,它将在子路径("zod/v4")导出,与 [email protected] 共存。
  • 尽管如此,Zod 4 被认为是稳定且已准备好用于生产环境的。
  • Zod 3 将继续从包根目录("zod")以及新的子路径 "zod/v3" 导出。它将继续接收错误修复和稳定性改进。

这种方法类似于 Golang 处理主版本更改的方式:https://go.dev/doc/modules/major-version

稍后:

  • 包根目录("zod")将从导出 Zod 3 切换到 Zod 4。
  • 此时 [email protected] 将发布到 npm。
  • "zod/v4" 子路径将永远保持可用。

为什么?

Zod 在生态系统中占据着独特的位置。生态系统中的许多库/框架都接受用户定义的 Zod schema。这意味着它们面向用户的 API 与 Zod 及其各种类/接口/实用工具紧密耦合。对于这些库/框架,Zod 的破坏性变更必然会导致其用户的破坏性变更。Zod 3 的 ZodType 不可分配给 Zod 4 的 ZodType

为什么库不能直接同时支持 v3 和 v4?

不幸的是,peerDependencies 的限制(以及包管理器之间的不一致)使得优雅地同时支持一个库的两个主要版本变得极其困难。

如果我天真地将 [email protected] 发布到 npm,Zod 生态系统中的绝大多数库都需要发布一个新的主要版本来正确支持 Zod 4,包括像 AI SDK 这样的一些知名库。这将引发整个生态系统的“版本更新雪崩”,并产生大量的挫败感和工作量。

通过子路径版本控制,我们解决了这个问题。它为库提供了一种直接的方式来同时支持 Zod 3 和 Zod 4(包括 Zod Mini)。它们可以继续在 "zod" 上定义单个 peerDependency;不需要像 npm 别名、可选对等依赖、"zod-compat" 包或其他此类黑客手段那样晦涩难懂的解决方案。

库需要将其 "zod" 对等依赖的最低版本提升到 zod@^3.25.0。然后,它们可以在实现中同时引用 Zod 3 和 Zod 4:

import * as z3 from "zod/v3"
import * as z4 from "zod/v4"

稍后,一旦有了对 v4 的广泛支持,我们将提升 npm 上的主版本,并开始从包根目录导出 Zod 4,完成过渡。(这已经发生了——请参阅本页顶部的说明。)

只要库专门从关联的子路径(而不是根目录)导入,它们的实现就会在主要版本更新中继续工作,而无需更改代码。

虽然这看起来可能非正统(至少对于不使用 Go 的人来说!),但这是我所知道的唯一一种能让 Zod 用户和更广泛生态系统中的库都拥有清晰、增量的迁移路径的方法。


深入探讨为何在这种情况下对等依赖(peer dependencies)不起作用。

想象一下,你是一个库,试图构建一个接受 Zod schema 的函数 acceptSchema。你希望能够接受 Zod 3 或 Zod 4 schema。在这个假设中,我想象 Zod 4 在 npm 上以 zod@4 发布,没有子路径。你的选择如下:

  1. 使用 npm 别名作为 dependencies 同时安装 zod@3 和 zod@4。这行得通,但你最终会包含你自己的 Zod 3 和 Zod 4 副本。你无法保证用户的 Zod schema 是你从依赖项中提取的同一个 z.ZodType 类的实例(instanceof 检查可能会失败)。

  2. 使用跨越多个主要版本的对等依赖:"zod@>=3.0.0" ……但在开发库时,你仍然需要选择一个版本进行开发。通常你会将其作为开发依赖安装。你有责任通过艰苦的努力确保你的代码在两个版本中都能逐字逐句地工作。这在 Zod 3 和 Zod 4 的情况下是不可能的,因为许多非常基础的类已经简化/更改了泛型。

  3. 可选的对等依赖。我只是找不到一个明确的答案,关于如何在所有平台上可靠地确定在运行时安装了哪个对等依赖。网上的许多答案会说“在 try/catch 中使用动态导入来检查包是否存在”。这些人假设你在后端,因为前端打包工具没有提供这种功能。当你尝试打包未安装的依赖项时,它们会失败。显然,你在构建步骤中是否处于 try/catch 内部并不重要。而且:由于我们谈论的是同一库的多个版本,你需要使用 npm 别名来区分 package.json 中的两个版本。像 v10 这样新近的 npm 版本无法处理对等依赖 + npm 别名的组合。

  4. zod-compat。在这个极其模糊的网传解决方案是“为每个代表某些基本功能的版本定义接口”。基本上是一些库可以用来近似真实情况的实用类型。这就容易出错,工作量巨大,需要与实际实现保持同步,最终库是针对可能缺乏细节的影子版本进行开发。而且它只适用于类型:如果一个库依赖于 Zod 中的任何运行时代码,它就会崩溃。

因此,子路径。

On this page