编解码器
✨ 新 — 在 zod@4.1 中引入
所有 Zod 模式都可以处理正向和反向的输入:
🌐 All Zod schemas can process inputs in both the forward and backward direction:
- 转发:
Input到Output.parse().decode()
- 向后:
Output到Input.encode()
在大多数情况下,这是一个没有区别的区分。输入和输出类型是相同的,所以“前向”和“后向”之间没有区别。
🌐 In most cases, this is a distinction without a difference. The input and output types are identical, so there's no difference between "forward" and "backward".
然而,一些模式类型会导致输入和输出类型发生分歧,尤其是 z.codec()。编解码器是一种特殊类型的模式,它定义了两个其他模式之间的双向转换。
🌐 However, some schema types cause the input and output types to diverge, notably z.codec(). Codecs are a special type of schema that defines a bi-directional transformation between two other schemas.
在这些情况下,z.decode() 和 z.encode() 的表现相当不同。
🌐 In these cases, z.decode() and z.encode() behave quite differently.
注意 —这里的指示或术语没有什么特别之处。你可以不用 A -> B 编解码器来编码,而是使用 B -> A 编解码器来解码。使用“解码”和“编码”这些术语只是一个约定而已。
当在网络边界解析数据时,这尤其有用。你可以在客户端和服务器之间共享一个 Zod 模式,然后使用这个单一模式在网络友好的格式(比如 JSON)和更丰富的 JavaScript 表示之间进行转换。
🌐 This is particularly useful when parsing data at a network boundary. You can share a single Zod schema between your client and server, then use this single schema to convert between a network-friendly format (say, JSON) and a richer JavaScript representation.
可组合性
🌐 Composability
注意 — 你可以在任何 schema 中使用 z.encode() 和 z.decode()。它不必是 ZodCodec。
编解码器和其他任何模式一样。你可以将它们嵌套在对象、数组、管道等内部。关于使用它们的位置没有规则!
🌐 Codecs are a schema like any other. You can nest them inside objects, arrays, pipes, etc. There are no rules on where you can use them!
类型安全输入
🌐 Type-safe inputs
虽然 .parse() 和 .decode() 在 运行时 表现相同,但它们的类型签名不同。.parse() 方法接受 unknown 作为输入,并返回一个与模式推断的 输出类型 匹配的值。相比之下,z.decode() 和 z.encode() 函数具有 强类型输入。
🌐 While .parse() and .decode() behave identically at runtime, they have different type signatures. The .parse() method accepts unknown as input, and returns a value that matches the schema's inferred output type. By contrast, the z.decode() and z.encode() functions have strongly-typed inputs.
为什么会有差异?编码和解码意味着转换。在许多情况下,这些方法的输入在应用代码中已经是强类型的,因此 z.decode/z.encode 接受强类型输入以在编译时显示错误。
下面是一个图表,展示了 parse()、decode() 和 encode() 的类型签名之间的差异。
🌐 Why the difference? Encoding and decoding imply transformation. In many cases, the inputs to these methods are already strongly typed in application code, so z.decode/z.encode accept strongly typed inputs to surface mistakes at compile time.
Here's a diagram demonstrating the differences between the type signatures for parse(), decode(), and encode().


异步和安全变体
🌐 Async and safe variants
与 .transform() 和 .refine() 一样,编解码器支持异步转换。
🌐 As with .transform() and .refine(), codecs support async transforms.
与常规的 parse() 一样,decode() 和 encode() 也有“安全”和“异步”变体。
🌐 As with regular parse(), there are "safe" and "async" variants of decode() and encode().
编码的工作原理
🌐 How encoding works
某些 Zod 模式如何“反转”它们的解析行为存在一些微妙之处。
🌐 There are some subtleties to how certain Zod schemas "reverse" their parse behavior.
编解码器
🌐 Codecs
这个相当容易理解。编解码器封装了两种类型之间的双向转换。z.decode() 触发 decode 转换,将输入转换为解析后的值,而 z.encode() 触发 encode 转换将其序列化回去。
🌐 This one is fairly self-explanatory. Codecs encapsulate a bi-directional transformation between two types. z.decode() triggers the decode transform to convert input into a parsed value, while z.encode() triggers the encode transform to serialize it back.
管道
🌐 Pipes
有趣的事实 — 编解码器实际上在内部是作为管道的子类实现的,这些管道经过增强,加入了“中间”转换逻辑。
在常规解码过程中,ZodPipe<A, B> 模式会先用 A 解析数据,然后将其传入 B。正如你可能预料的那样,在编码过程中,数据首先使用 B 编码,然后传入 A。
🌐 During regular decoding, a ZodPipe<A, B> schema will first parse the data with A, then pass it into B. As you might expect, during encoding, the data is first encoded with B, then passed into A.
细化
🌐 Refinements
所有检查(.refine()、.min()、.max() 等)仍然会在两个方向上执行。
🌐 All checks (.refine(), .min(), .max(), etc.) are still executed in both directions.
为了避免在自定义 .refine() 逻辑中出现意外错误,Zod 在 z.encode() 期间会执行两次“遍历”。第一次遍历确保输入类型符合预期类型(没有 invalid_type 错误)。如果第一次通过,Zod 会执行第二次遍历,执行精化逻辑。
🌐 To avoid unexpected errors in your custom .refine() logic, Zod performs two "passes" during z.encode(). The first pass ensures the input type conforms to the expected type (no invalid_type errors). If that passes, Zod performs the second pass which executes the refinement logic.
这种方法还支持像 z.string().trim() 或 z.string().toLowerCase() 这样的“修改转换”:
🌐 This approach also supports "mutating transforms" like z.string().trim() or z.string().toLowerCase():
默认值和预置错误
🌐 Defaults and prefaults
默认值和预取页仅在“前向”方向上应用。
🌐 Defaults and prefaults are only applied in the "forward" direction.
当你给一个模式附加默认值时,输入变为可选(| undefined),但输出则不是。因此,undefined 不是 z.encode() 的有效输入,并且默认值/预设值不会被应用。
🌐 When you attach a default value to a schema, the input becomes optional (| undefined) but the output does not. As such, undefined is not a valid input to z.encode() and defaults/prefaults will not be applied.
捕获
🌐 Catch
同样,.catch() 仅在“正向”方向应用。
🌐 Similarly, .catch() is only applied in the "forward" direction.
Stringbool
注意 — Stringbool 出现在 Zod 引入编解码器之前。此后,它已在内部被重新实现为一个编解码器。
z.stringbool() API 将字符串值("true"、"false"、"yes"、"no" 等)转换为 boolean。默认情况下,它将在 z.encode() 期间将 true 转换为 "true",并将 false 转换为 "false"。
🌐 The z.stringbool() API converts string values ("true", "false", "yes", "no", etc.) into boolean. By default, it will convert true to "true" and false to "false" during z.encode().
如果你指定了一组自定义的 truthy 和 falsy 值,将使用数组中的第一个元素。
🌐 If you specify a custom set of truthy and falsy values, the first element in the array will be used instead.
转换
🌐 Transforms
⚠️ — .transform() API 实现了单向转换。如果你的模式中任何地方存在 .transform(),尝试执行 z.encode() 操作将抛出运行时错误(而不是 ZodError)。
有用的编解码器
🌐 Useful codecs
以下是一些常用编解码器的实现。为了便于自定义,这些并未作为 Zod 自身的一级 API 提供。相反,你应该将它们复制/粘贴到你的项目中,并根据需要进行修改。
🌐 Below are implementations for a bunch of commonly-needed codecs. For the sake of customizability, these are not included as first-class APIs in Zod itself. Instead, you should copy/paste them into your project and modify them as needed.
注意 — 所有这些编解码器实现都已经过正确性测试。
stringToNumber
使用 parseFloat() 将数字的字符串表示转换为 JavaScript number 类型。
🌐 Converts string representations of numbers to JavaScript number type using parseFloat().
stringToInt
使用 parseInt() 将整数的字符串表示转换为 JavaScript number 类型。
🌐 Converts string representations of integers to JavaScript number type using parseInt().
stringToBigInt
将字符串表示转换为 JavaScript bigint 类型。
🌐 Converts string representations to JavaScript bigint type.
numberToBigInt
将 JavaScript number 转换为 bigint 类型。
🌐 Converts JavaScript number to bigint type.
isoDatetimeToDate
将 ISO 日期时间字符串转换为 JavaScript Date 对象。
🌐 Converts ISO datetime strings to JavaScript Date objects.
epochSecondsToDate
将 Unix 时间戳(自纪元以来的秒数)转换为 JavaScript Date 对象。
🌐 Converts Unix timestamps (seconds since epoch) to JavaScript Date objects.
epochMillisToDate
将 Unix 时间戳(自纪元以来的毫秒数)转换为 JavaScript Date 对象。
🌐 Converts Unix timestamps (milliseconds since epoch) to JavaScript Date objects.
json(schema)
将 JSON 字符串解析为结构化数据,并序列化回 JSON。此通用函数接受一个输出模式来验证解析后的 JSON 数据。
🌐 Parses JSON strings into structured data and serializes back to JSON. This generic function accepts an output schema to validate the parsed JSON data.
特定模式的使用示例:
🌐 Usage example with a specific schema:
utf8ToBytes
将 UTF-8 字符串转换为 Uint8Array 字节数组。
🌐 Converts UTF-8 strings to Uint8Array byte arrays.
bytesToUtf8
将 Uint8Array 字节数组转换为 UTF-8 字符串。
🌐 Converts Uint8Array byte arrays to UTF-8 strings.
base64ToBytes
将 base64 字符串转换为 Uint8Array 字节数组,反之亦然。
🌐 Converts base64 strings to Uint8Array byte arrays and vice versa.
base64urlToBytes
将 base64url 字符串(URL 安全的 base64)转换为 Uint8Array 字节数组。
🌐 Converts base64url strings (URL-safe base64) to Uint8Array byte arrays.
hexToBytes
将十六进制字符串转换为 Uint8Array 字节数组,反之亦然。
🌐 Converts hexadecimal strings to Uint8Array byte arrays and vice versa.
stringToURL
将 URL 字符串转换为 JavaScript URL 对象。
🌐 Converts URL strings to JavaScript URL objects.
stringToHttpURL
将 HTTP/HTTPS URL 字符串转换为 JavaScript URL 对象。
🌐 Converts HTTP/HTTPS URL strings to JavaScript URL objects.
uriComponent
使用 encodeURIComponent() 和 decodeURIComponent() 对 URI 组件进行编码和解码。
🌐 Encodes and decodes URI components using encodeURIComponent() and decodeURIComponent().

