zod

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Zod 4

Zod 4

TypeScript-first schema validation. 2kb core bundle (gzipped). Zero dependencies.
CRITICAL: Zod 4 is the current stable version (
zod@^4.0.0
). Always write Zod 4 code. Never use deprecated Zod 3 patterns.
优先支持TypeScript的Schema验证工具。核心包体积仅2kb(gzip压缩后),零依赖。
重要提示:Zod 4是当前稳定版本(
zod@^4.0.0
)。请始终编写Zod 4代码,切勿使用已废弃的Zod 3写法。

Import

导入

ts
import * as z from "zod";
For tree-shakable variant (smaller bundles):
ts
import * as z from "zod/mini";
ts
import * as z from "zod";
如需支持摇树优化的变体(更小的包体积):
ts
import * as z from "zod/mini";

Core Patterns

核心模式

Parsing

解析

ts
schema.parse(data);           // throws ZodError on failure
schema.safeParse(data);       // returns { success, data?, error? }
await schema.parseAsync(data);
await schema.safeParseAsync(data);
ts
schema.parse(data);           // 验证失败时抛出ZodError
schema.safeParse(data);       // 返回 { success, data?, error? }
await schema.parseAsync(data);
await schema.safeParseAsync(data);

Type Inference

类型推断

ts
type MyType = z.infer<typeof mySchema>;    // output type
type MyInput = z.input<typeof mySchema>;   // input type
type MyOutput = z.output<typeof mySchema>; // same as z.infer
ts
type MyType = z.infer<typeof mySchema>;    // 输出类型
type MyInput = z.input<typeof mySchema>;   // 输入类型
type MyOutput = z.output<typeof mySchema>; // 与z.infer结果一致

Primitives

原始类型

ts
z.string();
z.number();      // finite numbers only (no Infinity, no NaN)
z.bigint();
z.boolean();
z.symbol();
z.undefined();
z.null();
z.date();
z.nan();
ts
z.string();
z.number();      // 仅支持有限数字(不包含Infinity和NaN)
z.bigint();
z.boolean();
z.symbol();
z.undefined();
z.null();
z.date();
z.nan();

Coercion

类型转换

ts
z.coerce.string();    // String(input)
z.coerce.number();    // Number(input)
z.coerce.boolean();   // Boolean(input)
z.coerce.bigint();    // BigInt(input)
z.coerce.date();      // new Date(input)
ts
z.coerce.string();    // 执行String(input)转换
z.coerce.number();    // 执行Number(input)转换
z.coerce.boolean();   // 执行Boolean(input)转换
z.coerce.bigint();    // 执行BigInt(input)转换
z.coerce.date();      // 执行new Date(input)转换

String Formats (Top-Level)

字符串格式(顶层函数)

Use top-level functions, NOT methods. Methods like
z.string().email()
are deprecated.
ts
// CORRECT (Zod 4)
z.email();
z.uuid();
z.url();
z.httpUrl();
z.hostname();
z.emoji();
z.base64();
z.base64url();
z.hex();
z.jwt();
z.nanoid();
z.cuid();
z.cuid2();
z.ulid();
z.ipv4();
z.ipv6();
z.mac();
z.cidrv4();
z.cidrv6();
z.hash("sha256");     // "sha1" | "sha384" | "sha512" | "md5"
z.e164();              // phone numbers
z.iso.date();
z.iso.time();
z.iso.datetime();
z.iso.duration();

// DEPRECATED (Zod 3 style — do NOT use)
z.string().email();    // ❌
z.string().uuid();     // ❌
z.string().url();      // ❌
请使用顶层函数,而非方法。
z.string().email()
这类方法已被废弃
ts
// 正确写法(Zod 4)
z.email();
z.uuid();
z.url();
z.httpUrl();
z.hostname();
z.emoji();
z.base64();
z.base64url();
z.hex();
z.jwt();
z.nanoid();
z.cuid();
z.cuid2();
z.ulid();
z.ipv4();
z.ipv6();
z.mac();
z.cidrv4();
z.cidrv6();
z.hash("sha256");     // 支持 "sha1" | "sha384" | "sha512" | "md5"
z.e164();              // 电话号码格式
z.iso.date();
z.iso.time();
z.iso.datetime();
z.iso.duration();

// 已废弃(Zod 3写法 — 请勿使用)
z.string().email();    // ❌
z.string().uuid();     // ❌
z.string().url();      // ❌

UUID versions

UUID版本

ts
z.uuid();                    // any RFC 9562/4122 UUID
z.uuid({ version: "v4" });  // specific version
z.uuidv4();                  // convenience
z.uuidv6();
z.uuidv7();
z.guid();                    // any 8-4-4-4-12 hex pattern (less strict)
ts
z.uuid();                    // 支持任何符合RFC 9562/4122标准的UUID
z.uuid({ version: "v4" });  // 指定版本
z.uuidv4();                  // 便捷写法
z.uuidv6();
z.uuidv7();
z.guid();                    // 支持任何8-4-4-4-12格式的十六进制字符串(限制更宽松)

Custom email regex

自定义邮箱正则

ts
z.email();                                     // default (Gmail rules)
z.email({ pattern: z.regexes.html5Email });    // browser-style
z.email({ pattern: z.regexes.rfc5322Email });  // RFC 5322
z.email({ pattern: z.regexes.unicodeEmail });  // intl emails
ts
z.email();                                     // 默认规则(遵循Gmail规范)
z.email({ pattern: z.regexes.html5Email });    // 浏览器风格规则
z.email({ pattern: z.regexes.rfc5322Email });  // 遵循RFC 5322标准
z.email({ pattern: z.regexes.unicodeEmail });  // 支持国际化邮箱

JWTs

JWT

ts
z.jwt();
z.jwt({ alg: "HS256" });
ts
z.jwt();
z.jwt({ alg: "HS256" });

Numbers & Integers

数字与整数

ts
z.number();      // any finite number
z.int();         // safe integer range
z.int32();       // int32 range
z.float32();     // float32 range
z.float64();     // float64 range

// bigint variants
z.bigint();
z.int64();
z.uint64();
ts
z.number();      // 任何有限数字
z.int();         // 安全整数范围
z.int32();       // int32范围
z.float32();     // float32范围
z.float64();     // float64范围

// bigint变体
z.bigint();
z.int64();
z.uint64();

Number validations

数字验证规则

ts
z.number().gt(5);
z.number().gte(5);          // alias: .min(5)
z.number().lt(5);
z.number().lte(5);          // alias: .max(5)
z.number().positive();
z.number().nonnegative();
z.number().negative();
z.number().nonpositive();
z.number().multipleOf(5);   // alias: .step(5)
ts
z.number().gt(5);
z.number().gte(5);          // 别名: .min(5)
z.number().lt(5);
z.number().lte(5);          // 别名: .max(5)
z.number().positive();
z.number().nonnegative();
z.number().negative();
z.number().nonpositive();
z.number().multipleOf(5);   // 别名: .step(5)

String validations

字符串验证规则

ts
z.string().max(5);
z.string().min(5);
z.string().length(5);
z.string().regex(/pattern/);
z.string().startsWith("abc");
z.string().endsWith("xyz");
z.string().includes("---");
z.string().uppercase();
z.string().lowercase();
z.string().trim();
z.string().toLowerCase();
z.string().toUpperCase();
z.string().normalize();
ts
z.string().max(5);
z.string().min(5);
z.string().length(5);
z.string().regex(/pattern/);
z.string().startsWith("abc");
z.string().endsWith("xyz");
z.string().includes("---");
z.string().uppercase();
z.string().lowercase();
z.string().trim();
z.string().toLowerCase();
z.string().toUpperCase();
z.string().normalize();

Objects

对象

ts
z.object({ name: z.string(), age: z.number() });          // strips unknown keys
z.strictObject({ name: z.string() });                      // errors on unknown keys
z.looseObject({ name: z.string() });                       // passes unknown keys through
Deprecated:
.strict()
,
.passthrough()
,
.strip()
,
.merge()
,
.deepPartial()
.
ts
z.object({ name: z.string(), age: z.number() });          // 移除未知键
z.strictObject({ name: z.string() });                      // 存在未知键时抛出错误
z.looseObject({ name: z.string() });                       // 保留未知键
已废弃
.strict()
.passthrough()
.strip()
.merge()
.deepPartial()

Object methods

对象方法

ts
schema.extend({ newField: z.string() });    // add fields
schema.pick({ name: true });                // pick fields
schema.omit({ age: true });                 // omit fields
schema.partial();                           // all optional
schema.partial({ name: true });             // some optional
schema.required();                          // all required
schema.keyof();                             // ZodEnum from keys
schema.shape.name;                          // access inner schema
Prefer spread syntax for best tsc performance:
ts
z.object({ ...Base.shape, ...Extra.shape, newField: z.string() });
ts
schema.extend({ newField: z.string() });    // 添加字段
schema.pick({ name: true });                // 挑选指定字段
schema.omit({ age: true });                 // 排除指定字段
schema.partial();                           // 所有字段设为可选
schema.partial({ name: true });             // 指定部分字段为可选
schema.required();                          // 所有字段设为必填
schema.keyof();                             // 从键生成ZodEnum
schema.shape.name;                          // 访问内部Schema
为获得最佳TypeScript编译性能,推荐使用扩展语法:
ts
z.object({ ...Base.shape, ...Extra.shape, newField: z.string() });

Recursive objects

递归对象

ts
const Category = z.object({
  name: z.string(),
  get subcategories() {
    return z.array(Category);
  },
});
ts
const Category = z.object({
  name: z.string(),
  get subcategories() {
    return z.array(Category);
  },
});

Enums

枚举

ts
z.enum(["A", "B", "C"]);               // string enum
z.enum(MyTSEnum);                       // TypeScript enum (replaces z.nativeEnum())
z.enum({ A: 0, B: 1 } as const);       // enum-like object
Deprecated:
z.nativeEnum()
. Use
z.enum()
instead.
ts
z.enum(["A", "B", "C"]);               // 字符串枚举
z.enum(MyTSEnum);                       // TypeScript枚举(替代z.nativeEnum())
z.enum({ A: 0, B: 1 } as const);       // 类枚举对象
已废弃
z.nativeEnum()
。请使用
z.enum()
替代。

Arrays, Tuples, Sets, Maps

数组、元组、集合、映射

ts
z.array(z.string());
z.array(z.string()).min(1).max(10).length(5);
z.tuple([z.string(), z.number()]);
z.tuple([z.string()], z.number());    // variadic: [string, ...number[]]
z.set(z.number());
z.map(z.string(), z.number());
ts
z.array(z.string());
z.array(z.string()).min(1).max(10).length(5);
z.tuple([z.string(), z.number()]);
z.tuple([z.string()], z.number());    // 可变参数: [string, ...number[]]
z.set(z.number());
z.map(z.string(), z.number());

Unions & Intersections

联合类型与交叉类型

ts
z.union([z.string(), z.number()]);
z.discriminatedUnion("status", [
  z.object({ status: z.literal("ok"), data: z.string() }),
  z.object({ status: z.literal("err"), error: z.string() }),
]);
z.xor([z.string(), z.number()]);          // exclusive union (exactly one match)
z.intersection(schemaA, schemaB);
ts
z.union([z.string(), z.number()]);
z.discriminatedUnion("status", [
  z.object({ status: z.literal("ok"), data: z.string() }),
  z.object({ status: z.literal("err"), error: z.string() }),
]);
z.xor([z.string(), z.number()]);          // 互斥联合类型(仅匹配其中一个)
z.intersection(schemaA, schemaB);

Records

记录类型

ts
z.record(z.string(), z.number());                    // Record<string, number>
z.record(z.enum(["a", "b"]), z.string());            // exhaustive: { a: string; b: string }
z.partialRecord(z.enum(["a", "b"]), z.string());     // partial: { a?: string; b?: string }
z.looseRecord(z.string().regex(/^x_/), z.number());  // pass through non-matching keys
Breaking:
z.record(z.string())
single-arg form is removed. Always pass both key and value schemas.
ts
z.record(z.string(), z.number());                    // Record<string, number>
z.record(z.enum(["a", "b"]), z.string());            // 完全匹配: { a: string; b: string }
z.partialRecord(z.enum(["a", "b"]), z.string());     // 部分匹配: { a?: string; b?: string }
z.looseRecord(z.string().regex(/^x_/), z.number());  // 保留不匹配的键
破坏性变更
z.record(z.string())
单参数写法已移除。请始终传入键和值的Schema。

Literals

字面量

ts
z.literal("hello");
z.literal(42);
z.literal(true);
z.literal(["a", "b", "c"]);   // multi-value literal (new in Zod 4)
ts
z.literal("hello");
z.literal(42);
z.literal(true);
z.literal(["a", "b", "c"]);   // 多值字面量(Zod 4新增)

Files

文件

ts
z.file();
z.file().min(10_000);                          // min size in bytes
z.file().max(1_000_000);                       // max size in bytes
z.file().mime("image/png");                    // single MIME
z.file().mime(["image/png", "image/jpeg"]);    // multiple MIMEs
ts
z.file();
z.file().min(10_000);                          // 最小文件大小(字节)
z.file().max(1_000_000);                       // 最大文件大小(字节)
z.file().mime("image/png");                    // 单一MIME类型
z.file().mime(["image/png", "image/jpeg"]);    // 多种MIME类型

Stringbool

Stringbool类型

ts
z.stringbool();    // "true"/"yes"/"1"/"on"/"y"/"enabled" → true, inverses → false
z.stringbool({ truthy: ["yes", "y"], falsy: ["no", "n"] });
z.stringbool({ case: "sensitive" });
ts
z.stringbool();    // "true"/"yes"/"1"/"on"/"y"/"enabled" 转换为true,反之转换为false
z.stringbool({ truthy: ["yes", "y"], falsy: ["no", "n"] });
z.stringbool({ case: "sensitive" });

Template Literals

模板字面量

ts
z.templateLiteral(["hello, ", z.string()]);                    // `hello, ${string}`
z.templateLiteral([z.number(), z.enum(["px", "em", "rem"])]);  // `${number}px` | ...
ts
z.templateLiteral(["hello, ", z.string()]);                    // `hello, ${string}`
z.templateLiteral([z.number(), z.enum(["px", "em", "rem"])]);  // `${number}px` | ...

Optionals, Nullables, Defaults

可选类型、可空类型、默认值

ts
z.optional(z.string());          // or z.string().optional()
z.nullable(z.string());          // or z.string().nullable()
z.nullish(z.string());           // optional + nullable

z.string().default("hello");     // short-circuits on undefined, returns output type
z.string().prefault("hello");    // pre-parse default, runs through validation
z.number().catch(42);            // fallback on any validation error
Breaking:
.default()
now expects output type, not input type. Use
.prefault()
for old behavior.
ts
z.optional(z.string());          // 等价于 z.string().optional()
z.nullable(z.string());          // 等价于 z.string().nullable()
z.nullish(z.string());           // 可选 + 可空

z.string().default("hello");     // 当值为undefined时返回默认值,返回结果为输出类型
z.string().prefault("hello");    // 先应用默认值,再执行验证
z.number().catch(42);            // 验证失败时返回 fallback 值
破坏性变更
.default()
现在期望传入输出类型的值,而非输入类型。如需旧版行为,请使用
.prefault()

Transforms & Pipes

转换与管道

ts
z.transform((val) => String(val));                      // standalone transform
z.string().transform((val) => val.length);              // pipe string → transform
z.preprocess((val) => String(val), z.string());         // transform → pipe to schema
z.string().pipe(z.transform((val) => val.length));      // explicit pipe

// .overwrite() — transform without changing inferred type
z.number().overwrite((val) => val ** 2);
ts
z.transform((val) => String(val));                      // 独立转换
z.string().transform((val) => val.length);              // 字符串 → 转换
z.preprocess((val) => String(val), z.string());         // 转换 → 传入Schema验证
z.string().pipe(z.transform((val) => val.length));      // 显式管道

// .overwrite() — 转换但不改变推断类型
z.number().overwrite((val) => val ** 2);

Codecs (Bidirectional Transforms)

Codecs(双向转换)

New in Zod 4.1. Define encode/decode pairs:
ts
const stringToDate = z.codec(z.iso.datetime(), z.date(), {
  decode: (s) => new Date(s),
  encode: (d) => d.toISOString(),
});

stringToDate.decode("2024-01-15T10:30:00.000Z");  // → Date
stringToDate.encode(new Date());                    // → string
stringToDate.parse("2024-01-15T10:30:00.000Z");    // → Date (same as decode at runtime)
Zod 4.1新增功能。定义编码/解码对:
ts
const stringToDate = z.codec(z.iso.datetime(), z.date(), {
  decode: (s) => new Date(s),
  encode: (d) => d.toISOString(),
});

stringToDate.decode("2024-01-15T10:30:00.000Z");  // → Date对象
stringToDate.encode(new Date());                    // → 字符串
stringToDate.parse("2024-01-15T10:30:00.000Z");    // → Date对象(运行时与decode行为一致)

Error Customization

错误自定义

Use unified
error
param (replaces
message
,
errorMap
,
invalid_type_error
,
required_error
):
ts
z.string().min(5, { error: "Too short" });
z.string({ error: (issue) => issue.input === undefined ? "Required" : "Not a string" });
z.string({ error: (issue) => {
  if (issue.code === "too_small") return `Min ${issue.minimum}`;
}});
Deprecated:
message
,
errorMap
,
invalid_type_error
,
required_error
.
使用统一的
error
参数(替代
message
errorMap
invalid_type_error
required_error
):
ts
z.string().min(5, { error: "长度过短" });
z.string({ error: (issue) => issue.input === undefined ? "必填项" : "不是字符串类型" });
z.string({ error: (issue) => {
  if (issue.code === "too_small") return `最小长度为 ${issue.minimum}`;
}});
已废弃
message
errorMap
invalid_type_error
required_error

Metadata & Registries

元数据与注册表

ts
z.string().meta({ id: "email", title: "Email", description: "User email" });
z.string().describe("A description");      // shorthand for .meta({ description: ... })

// Custom registries
const myReg = z.registry<{ description: string }>();
z.string().register(myReg, { description: "..." });
ts
z.string().meta({ id: "email", title: "邮箱", description: "用户邮箱" });
z.string().describe("描述信息");      // .meta({ description: ... }) 的简写

// 自定义注册表
const myReg = z.registry<{ description: string }>();
z.string().register(myReg, { description: "..." });

JSON Schema

JSON Schema

ts
z.toJSONSchema(schema);                                        // Zod → JSON Schema
z.toJSONSchema(schema, { target: "draft-07" });                // specific draft
z.toJSONSchema(schema, { target: "openapi-3.0" });             // OpenAPI 3.0
z.fromJSONSchema(jsonSchema);                                  // JSON Schema → Zod (experimental)
ts
z.toJSONSchema(schema);                                        // Zod → JSON Schema
z.toJSONSchema(schema, { target: "draft-07" });                // 指定JSON Schema版本
z.toJSONSchema(schema, { target: "openapi-3.0" });             // OpenAPI 3.0
z.fromJSONSchema(jsonSchema);                                  // JSON Schema → Zod(实验性功能)

Refinements

自定义验证

ts
z.string().refine((val) => val.includes("@"), { error: "Must contain @" });
z.string().refine((val) => val.includes("@"), { error: "...", abort: true }); // stop on failure
z.array(z.string()).superRefine((val, ctx) => {
  ctx.addIssue({ code: "custom", message: "...", input: val });
});
Refinements now live inside schemas (not
ZodEffects
wrapper). You can interleave
.refine()
with other methods:
ts
z.string().refine(v => v.includes("@")).min(5);  // works in Zod 4!
ts
z.string().refine((val) => val.includes("@"), { error: "必须包含@符号" });
z.string().refine((val) => val.includes("@"), { error: "...", abort: true }); // 验证失败时终止后续检查
z.array(z.string()).superRefine((val, ctx) => {
  ctx.addIssue({ code: "custom", message: "...", input: val });
});
自定义验证现在直接集成在Schema中(不再使用
ZodEffects
包装器)。你可以在其他方法之间穿插使用
.refine()
ts
z.string().refine(v => v.includes("@")).min(5);  // Zod 4中支持此写法!

Error Pretty-Printing

错误美化输出

ts
z.prettifyError(zodError);   // formatted multi-line string
z.treeifyError(zodError);    // tree structure (replaces .format() and .flatten())
ts
z.prettifyError(zodError);   // 格式化多行字符串
z.treeifyError(zodError);    // 树形结构(替代.format()和.flatten())

Further Reference

更多参考

  • Zod Mini: See references/zod-mini.md for tree-shakable API differences,
    .check()
    usage, and bundle size tradeoffs
  • Codecs: See references/codecs.md for bidirectional transforms, encoding behavior, and common codec patterns (stringToDate, jsonCodec, etc.)
  • JSON Schema: See references/json-schema.md for
    z.toJSONSchema()
    options, format conversion, registry-based multi-schema, and
    z.fromJSONSchema()
  • Advanced patterns: See references/advanced.md for registries, refinement
    when
    ,
    .superRefine()
    ,
    .check()
    , functions, branded types, readonly, custom schemas, and advanced string/object/record/union options
  • Migration from Zod 3: See references/migration.md for all breaking changes and deprecated APIs
  • Zod Mini:查看references/zod-mini.md了解支持摇树优化的API差异、
    .check()
    用法及包体积权衡
  • Codecs:查看references/codecs.md了解双向转换、编码行为及常见Codec模式(stringToDate、jsonCodec等)
  • JSON Schema:查看references/json-schema.md了解
    z.toJSONSchema()
    选项、格式转换、基于注册表的多Schema及
    z.fromJSONSchema()
  • 高级模式:查看references/advanced.md了解注册表、自定义验证
    when
    .superRefine()
    .check()
    、函数、品牌类型、只读、自定义Schema及高级字符串/对象/记录/联合类型选项
  • 从Zod 3迁移:查看references/migration.md了解所有破坏性变更及已废弃API