npx skills add https://github.com/secondsky/claude-skills --skill zodZod 是一个 TypeScript 优先的验证库,使开发者能够在运行时定义模式以验证数据,同时自动推断静态 TypeScript 类型。Zod 零依赖,核心包大小仅 2kb(gzip 压缩),提供不可变的、可组合的验证以及全面的错误处理。
bun add zod
# 或
bun add zod
# 或
bun add zod
# 或
yarn add zod
要求:
tsconfig.json 中设置 "strict": true重要提示:此技能文档记录的是 Zod 4.x 功能。以下 API 需要 Zod 4,在 Zod 3.x 中不可用:
z.codec() - 双向转换z.iso.date(), z.iso.time(), z.iso.datetime(), - ISO 格式验证器广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
z.iso.duration()z.toJSONSchema() - JSON Schema 生成z.treeifyError(), z.prettifyError(), z.flattenError() - 新的错误格式化辅助函数.meta() - 增强的元数据(Zod 3.x 只有 .describe())error 参数 - 替代 message, invalid_type_error, required_error, errorMap关于 Zod 3.x 的兼容性或迁移指南,请参阅 https://zod.dev
加载 references/migration-guide.md 以获取完整的 v3 到 v4 迁移文档。
Zod v4 引入了破坏性变更以获得更好的性能:
error 参数(替代 message, invalid_type_error, required_error)Infinity 和不安全的整数z.email() 对比 z.string().email()).extend()(而非 .merge()),z.treeifyError()(而非 error.format()).implement() 方法→ 加载 references/migration-guide.md 以获取: 完整的破坏性变更、迁移清单、渐进式迁移策略、回滚说明
import { z } from "zod";
// 定义模式
const UserSchema = z.object({
username: z.string(),
age: z.number().int().positive(),
email: z.string().email(),
});
// 推断 TypeScript 类型
type User = z.infer<typeof UserSchema>;
// 验证数据(出错时抛出异常)
const user = UserSchema.parse(data);
// 验证数据(返回结果对象)
const result = UserSchema.safeParse(data);
if (result.success) {
console.log(result.data); // 已类型化!
} else {
console.error(result.error); // ZodError
}
根据错误处理需求使用适当的解析方法:
.parse(data) - 输入无效时抛出 ZodError;成功时返回强类型数据.safeParse(data) - 返回 { success: true, data } 或 { success: false, error }(不抛出异常).parseAsync(data) - 用于包含异步细化/转换的模式.safeParseAsync(data) - 不抛出异常的异步版本最佳实践:使用 .safeParse() 以避免 try-catch 块,并利用可辨识联合类型。
z.string() // 基本字符串
z.string().min(5) // 最小长度
z.string().max(100) // 最大长度
z.string().length(10) // 精确长度
z.string().email() // 邮箱验证
z.string().url() // URL 验证
z.string().uuid() // UUID 格式
z.string().regex(/^\d+$/) // 自定义模式
z.string().startsWith("pre") // 前缀检查
z.string().endsWith("suf") // 后缀检查
z.string().trim() // 自动修剪空白字符
z.string().toLowerCase() // 自动转为小写
z.string().toUpperCase() // 自动转为大写
// ISO 格式(Zod 4+)
z.iso.date() // YYYY-MM-DD
z.iso.time() // HH:MM:SS
z.iso.datetime() // ISO 8601 日期时间
z.iso.duration() // ISO 8601 持续时间
// 网络格式
z.ipv4() // IPv4 地址
z.ipv6() // IPv6 地址
z.cidrv4() // IPv4 CIDR 表示法
z.cidrv6() // IPv6 CIDR 表示法
// 其他格式
z.jwt() // JWT 令牌
z.nanoid() // Nanoid
z.cuid() // CUID
z.cuid2() // CUID2
z.ulid() // ULID
z.base64() // Base64 编码
z.hex() // 十六进制
z.number() // 基本数字
z.number().int() // 仅整数
z.number().positive() // > 0
z.number().nonnegative() // >= 0
z.number().negative() // < 0
z.number().nonpositive() // <= 0
z.number().min(0) // 最小值
z.number().max(100) // 最大值
z.number().gt(0) // 大于
z.number().gte(0) // 大于或等于
z.number().lt(100) // 小于
z.number().lte(100) // 小于或等于
z.number().multipleOf(5) // 必须是 5 的倍数
z.int() // z.number().int() 的简写
z.int32() // 32 位整数
z.nan() // NaN 值
z.coerce.string() // 转换为字符串
z.coerce.number() // 转换为数字
z.coerce.boolean() // 转换为布尔值
z.coerce.bigint() // 转换为 bigint
z.coerce.date() // 转换为 Date
// 示例:解析查询参数
const QuerySchema = z.object({
page: z.coerce.number().int().positive(),
limit: z.coerce.number().int().max(100).default(10),
});
// "?page=5&limit=20" -> { page: 5, limit: 20 }
z.boolean() // 布尔值
z.date() // Date 对象
z.date().min(new Date("2020-01-01"))
z.date().max(new Date("2030-12-31"))
z.bigint() // BigInt
z.symbol() // Symbol
z.null() // Null
z.undefined() // Undefined
z.void() // Void (undefined)
const PersonSchema = z.object({
name: z.string(),
age: z.number(),
address: z.object({
street: z.string(),
city: z.string(),
country: z.string(),
}),
});
type Person = z.infer<typeof PersonSchema>;
// 对象方法
PersonSchema.shape // 访问形状
PersonSchema.keyof() // 获取键的联合类型
PersonSchema.extend({ role: z.string() }) // 添加字段
PersonSchema.pick({ name: true }) // 选取特定字段
PersonSchema.omit({ age: true }) // 省略字段
PersonSchema.partial() // 使所有字段可选
PersonSchema.required() // 使所有字段必填
PersonSchema.deepPartial() // 递归可选
// 严格对象 vs 宽松对象
z.strictObject({ ... }) // 不允许额外键(抛出异常)
z.object({ ... }) // 剥离额外键(默认)
z.looseObject({ ... }) // 允许额外键
z.array(z.string()) // 字符串数组
z.array(z.number()).min(1) // 至少 1 个元素
z.array(z.number()).max(10) // 最多 10 个元素
z.array(z.number()).length(5) // 恰好 5 个元素
z.array(z.number()).nonempty() // 至少 1 个元素
// 嵌套数组
z.array(z.array(z.number())) // number[][]
z.tuple([z.string(), z.number()]) // [string, number]
z.tuple([z.string(), z.number()]).rest(z.boolean()) // [string, number, ...boolean[]]
// 枚举
const RoleEnum = z.enum(["admin", "user", "guest"]);
type Role = z.infer<typeof RoleEnum>; // "admin" | "user" | "guest"
// 字面量值
z.literal("exact_value")
z.literal(42)
z.literal(true)
// 原生 TypeScript 枚举
enum Fruits {
Apple,
Banana,
}
z.nativeEnum(Fruits)
// 枚举方法
RoleEnum.enum.admin // "admin"
RoleEnum.exclude(["guest"]) // 排除值
RoleEnum.extract(["admin", "user"]) // 仅包含
// 基本联合类型
z.union([z.string(), z.number()])
// 可辨识联合类型(更好的性能和类型推断)
const ResponseSchema = z.discriminatedUnion("status", [
z.object({ status: z.literal("success"), data: z.any() }),
z.object({ status: z.literal("error"), message: z.string() }),
]);
type Response = z.infer<typeof ResponseSchema>;
// { status: "success", data: any } | { status: "error", message: string }
const BaseSchema = z.object({ id: z.string() });
const ExtendedSchema = z.object({ name: z.string() });
const Combined = z.intersection(BaseSchema, ExtendedSchema);
// 等价于:z.object({ id: z.string(), name: z.string() })
// 记录:具有类型化键和值的对象
z.record(z.string()) // { [key: string]: string }
z.record(z.string(), z.number()) // { [key: string]: number }
// 部分记录(某些键可选)
z.partialRecord(z.enum(["a", "b"]), z.string())
// 映射
z.map(z.string(), z.number()) // Map<string, number>
z.set(z.string()) // Set<string>
加载 references/advanced-patterns.md 以获取完整的高级验证和转换模式。
细化(自定义验证):
z.string().refine((val) => val.length >= 8, "Too short");
z.object({ password, confirmPassword }).superRefine((data, ctx) => { /* ... */ });
转换(修改数据):
z.string().transform((val) => val.trim());
z.string().pipe(z.coerce.number());
编解码器(双向转换 - v4.1 新增):
const DateCodec = z.codec(
z.iso.datetime(),
z.date(),
{
decode: (str) => new Date(str),
encode: (date) => date.toISOString(),
}
);
递归类型:
const CategorySchema: z.ZodType<Category> = z.lazy(() =>
z.object({ name: z.string(), subcategories: z.array(CategorySchema) })
);
可选/可空:
z.string().optional() // string | undefined
z.string().nullable() // string | null
z.string().default("default") // 如果未定义则提供默认值
只读和品牌:
z.object({ ... }).readonly() // 只读属性
z.string().brand<"UserId">() // 名义类型
→ 加载 references/advanced-patterns.md 以获取: 完整的细化模式、异步验证、编解码器示例、可组合模式、条件验证、性能优化
加载 references/error-handling.md 以获取完整的错误格式化和自定义指南。
错误格式化方法:
// 用于表单
const { fieldErrors } = z.flattenError(error);
// 用于嵌套数据
const tree = z.treeifyError(error);
const nameError = tree.properties?.user?.properties?.name?.errors?.[0];
// 用于调试
console.log(z.prettifyError(error));
自定义错误消息(三个级别):
// 1. 模式级别(最高优先级)
z.string({ error: "Custom message" });
z.string().min(5, "Too short");
// 2. 每次解析级别
schema.parse(data, { error: (issue) => ({ message: "..." }) });
// 3. 全局级别
z.config({ customError: (issue) => ({ message: "..." }) });
本地化(40+ 种语言):
z.config(z.locales.es()); // 西班牙语
z.config(z.locales.fr()); // 法语
→ 加载 references/error-handling.md 以获取: 完整的错误格式化示例、自定义错误模式、本地化设置、错误代码参考
加载 references/type-inference.md 以获取完整的类型推断和元数据文档。
基本类型推断:
const UserSchema = z.object({ name: z.string() });
type User = z.infer<typeof UserSchema>; // { name: string }
输入 vs 输出(用于转换):
const TransformSchema = z.string().transform((s) => s.length);
type Input = z.input<typeof TransformSchema>; // string
type Output = z.output<typeof TransformSchema>; // number
JSON Schema 转换:
const jsonSchema = z.toJSONSchema(UserSchema, {
target: "openapi-3.0",
metadata: true,
});
元数据:
// 添加元数据
const EmailSchema = z.string().email().meta({
title: "Email Address",
description: "User's email address",
});
// 创建自定义注册表
const formRegistry = z.registry<FormFieldMeta>();
→ 加载 references/type-inference.md 以获取: 完整的类型推断模式、JSON Schema 选项、元数据系统、自定义注册表、品牌类型
验证函数的输入和输出:
const AddFunction = z.function()
.args(z.number(), z.number()) // 参数
.returns(z.number()); // 返回类型
// 实现类型化函数
const add = AddFunction.implement((a, b) => {
return a + b; // 类型检查!
});
// 异步函数
const FetchFunction = z.function()
.args(z.string())
.returns(z.promise(z.object({ data: z.any() })))
.implementAsync(async (url) => {
const response = await fetch(url);
return response.json();
});
const EnvSchema = z.object({
NODE_ENV: z.enum(["development", "production", "test"]),
DATABASE_URL: z.string().url(),
PORT: z.coerce.number().int().positive().default(3000),
API_KEY: z.string().min(32),
});
// 在启动时验证
const env = EnvSchema.parse(process.env);
// 现在使用类型化的环境变量
console.log(env.PORT); // number
const CreateUserRequest = z.object({
username: z.string().min(3).max(20),
email: z.string().email(),
password: z.string().min(8),
age: z.number().int().positive().optional(),
});
// Express 示例
app.post("/users", async (req, res) => {
const result = CreateUserRequest.safeParse(req.body);
if (!result.success) {
return res.status(400).json({
errors: z.flattenError(result.error).fieldErrors,
});
}
const user = await createUser(result.data);
res.json(user);
});
const FormSchema = z.object({
firstName: z.string().min(1, "First name required"),
lastName: z.string().min(1, "Last name required"),
email: z.string().email("Invalid email"),
age: z.coerce.number().int().min(18, "Must be 18+"),
agreeToTerms: z.literal(true, {
errorMap: () => ({ message: "Must accept terms" }),
}),
});
type FormData = z.infer<typeof FormSchema>;
const UserSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
});
// 用于 PATCH 请求:使除 id 外的所有字段可选
const UpdateUserSchema = UserSchema.partial().required({ id: true });
type UpdateUser = z.infer<typeof UpdateUserSchema>;
// { id: string; name?: string; email?: string }
// 基础模式
const TimestampSchema = z.object({
createdAt: z.date(),
updatedAt: z.date(),
});
const AuthorSchema = z.object({
authorId: z.string(),
authorName: z.string(),
});
// 组合成更大的模式
const PostSchema = z.object({
id: z.string(),
title: z.string(),
content: z.string(),
}).merge(TimestampSchema).merge(AuthorSchema);
加载 references/ecosystem-integrations.md 以获取完整的框架和工具集成指南。
ESLint 插件:
eslint-plugin-zod-x - 强制执行最佳实践eslint-plugin-import-zod - 强制执行导入风格框架集成:
react-hook-form-zod 技能)代码生成:
→ 加载 references/ecosystem-integrations.md 以获取: 设置说明、集成示例、Hono 中间件、Drizzle ORM 模式
加载 references/troubleshooting.md 以获取完整的故障排除指南、性能提示和最佳实践。
常见问题:
tsconfig.json 中启用z.lazy() 进行代码分割z.lazy()z.discriminatedUnion().refine() 进行验证,.transform() 进行修改性能提示:
.discriminatedUnion()(比 .union() 快 5-10 倍).safeParse()(避免 try-catch 开销)最佳实践:
z.infer).meta() 进行文档化→ 加载 references/troubleshooting.md 以获取: 详细解决方案、性能优化、最佳实践、测试模式
// 原始类型
z.string(), z.number(), z.boolean(), z.date(), z.bigint()
// 集合
z.array(), z.tuple(), z.object(), z.record(), z.map(), z.set()
// 特殊类型
z.enum(), z.union(), z.discriminatedUnion(), z.intersection()
z.literal(), z.any(), z.unknown(), z.never()
// 修饰符
.optional(), .nullable(), .nullish(), .default(), .catch()
.readonly(), .brand()
// 验证
.min(), .max(), .length(), .regex(), .email(), .url(), .uuid()
.refine(), .superRefine()
// 转换
.transform(), .pipe(), .codec()
// 解析
.parse(), .safeParse(), .parseAsync(), .safeParseAsync()
// 类型推断
z.infer<typeof Schema>, z.input<typeof Schema>, z.output<typeof Schema>
// 错误处理
z.flattenError(), z.treeifyError(), z.prettifyError()
// JSON Schema
z.toJSONSchema(schema, options)
// 元数据
.meta(), .describe()
// 对象方法
.extend(), .pick(), .omit(), .partial(), .required(), .merge()
加载 references/migration-guide.md 当:
.merge(), error.format() 等)相关的错误时Infinity 或不安全整数的数字验证问题时加载 references/error-handling.md 当:
z.flattenError(), z.treeifyError() 或 z.prettifyError() 的问题时加载 references/advanced-patterns.md 当:
.refine(), .transform() 或 .codec() 的问题时加载 references/type-inference.md 当:
z.infer, z.input, z.output 的问题时加载 references/ecosystem-integrations.md 当:
加载 references/troubleshooting.md 当:
.refine() 和 .transform() 时生产说明:
此版本新增内容:
每周安装次数
157
代码仓库
GitHub 星标数
90
首次出现
Jan 24, 2026
安全审计
安装于
opencode127
gemini-cli119
github-copilot117
codex117
claude-code114
cursor111
Zod is a TypeScript-first validation library that enables developers to define schemas for validating data at runtime while automatically inferring static TypeScript types. With zero dependencies and a 2kb core bundle (gzipped), Zod provides immutable, composable validation with comprehensive error handling.
bun add zod
# or
bun add zod
# or
bun add zod
# or
yarn add zod
Requirements :
"strict": true in tsconfig.jsonImportant : This skill documents Zod 4.x features. The following APIs require Zod 4 and are NOT available in Zod 3.x:
z.codec() - Bidirectional transformationsz.iso.date(), z.iso.time(), z.iso.datetime(), z.iso.duration() - ISO format validatorsz.toJSONSchema() - JSON Schema generationz.treeifyError(), z.prettifyError(), z.flattenError() - New error formatting helpers.meta() - Enhanced metadata (Zod 3.x only has .describe())error parameter - Replaces message, invalid_type_error, required_error, errorMapFor Zod 3.x compatibility or migration guidance, see https://zod.dev
Loadreferences/migration-guide.md for complete v3 to v4 migration documentation.
Zod v4 introduces breaking changes for better performance:
error parameter (replaces message, invalid_type_error, required_error)Infinity and unsafe integersz.email() vs z.string().email()).extend() (not .merge()), (not )→ Loadreferences/migration-guide.md for: Complete breaking changes, migration checklist, gradual migration strategy, rollback instructions
import { z } from "zod";
// Define schema
const UserSchema = z.object({
username: z.string(),
age: z.number().int().positive(),
email: z.string().email(),
});
// Infer TypeScript type
type User = z.infer<typeof UserSchema>;
// Validate data (throws on error)
const user = UserSchema.parse(data);
// Validate data (returns result object)
const result = UserSchema.safeParse(data);
if (result.success) {
console.log(result.data); // Typed!
} else {
console.error(result.error); // ZodError
}
Use the appropriate parsing method based on error handling needs:
.parse(data) - Throws ZodError on invalid input; returns strongly-typed data on success.safeParse(data) - Returns { success: true, data } or { success: false, error } (no exceptions).parseAsync(data) - For schemas with async refinements/transforms.safeParseAsync(data) - Async version that doesn't throwBest Practice : Use .safeParse() to avoid try-catch blocks and leverage discriminated unions.
z.string() // Basic string
z.string().min(5) // Minimum length
z.string().max(100) // Maximum length
z.string().length(10) // Exact length
z.string().email() // Email validation
z.string().url() // URL validation
z.string().uuid() // UUID format
z.string().regex(/^\d+$/) // Custom pattern
z.string().startsWith("pre") // Prefix check
z.string().endsWith("suf") // Suffix check
z.string().trim() // Auto-trim whitespace
z.string().toLowerCase() // Auto-lowercase
z.string().toUpperCase() // Auto-uppercase
// ISO formats (Zod 4+)
z.iso.date() // YYYY-MM-DD
z.iso.time() // HH:MM:SS
z.iso.datetime() // ISO 8601 datetime
z.iso.duration() // ISO 8601 duration
// Network formats
z.ipv4() // IPv4 address
z.ipv6() // IPv6 address
z.cidrv4() // IPv4 CIDR notation
z.cidrv6() // IPv6 CIDR notation
// Other formats
z.jwt() // JWT token
z.nanoid() // Nanoid
z.cuid() // CUID
z.cuid2() // CUID2
z.ulid() // ULID
z.base64() // Base64 encoded
z.hex() // Hexadecimal
z.number() // Basic number
z.number().int() // Integer only
z.number().positive() // > 0
z.number().nonnegative() // >= 0
z.number().negative() // < 0
z.number().nonpositive() // <= 0
z.number().min(0) // Minimum value
z.number().max(100) // Maximum value
z.number().gt(0) // Greater than
z.number().gte(0) // Greater than or equal
z.number().lt(100) // Less than
z.number().lte(100) // Less than or equal
z.number().multipleOf(5) // Must be multiple of 5
z.int() // Shorthand for z.number().int()
z.int32() // 32-bit integer
z.nan() // NaN value
z.coerce.string() // Convert to string
z.coerce.number() // Convert to number
z.coerce.boolean() // Convert to boolean
z.coerce.bigint() // Convert to bigint
z.coerce.date() // Convert to Date
// Example: Parse query parameters
const QuerySchema = z.object({
page: z.coerce.number().int().positive(),
limit: z.coerce.number().int().max(100).default(10),
});
// "?page=5&limit=20" -> { page: 5, limit: 20 }
z.boolean() // Boolean
z.date() // Date object
z.date().min(new Date("2020-01-01"))
z.date().max(new Date("2030-12-31"))
z.bigint() // BigInt
z.symbol() // Symbol
z.null() // Null
z.undefined() // Undefined
z.void() // Void (undefined)
const PersonSchema = z.object({
name: z.string(),
age: z.number(),
address: z.object({
street: z.string(),
city: z.string(),
country: z.string(),
}),
});
type Person = z.infer<typeof PersonSchema>;
// Object methods
PersonSchema.shape // Access shape
PersonSchema.keyof() // Get union of keys
PersonSchema.extend({ role: z.string() }) // Add fields
PersonSchema.pick({ name: true }) // Pick specific fields
PersonSchema.omit({ age: true }) // Omit fields
PersonSchema.partial() // Make all fields optional
PersonSchema.required() // Make all fields required
PersonSchema.deepPartial() // Recursively optional
// Strict vs loose objects
z.strictObject({ ... }) // No extra keys allowed (throws)
z.object({ ... }) // Strips extra keys (default)
z.looseObject({ ... }) // Allows extra keys
z.array(z.string()) // String array
z.array(z.number()).min(1) // At least 1 element
z.array(z.number()).max(10) // At most 10 elements
z.array(z.number()).length(5) // Exactly 5 elements
z.array(z.number()).nonempty() // At least 1 element
// Nested arrays
z.array(z.array(z.number())) // number[][]
z.tuple([z.string(), z.number()]) // [string, number]
z.tuple([z.string(), z.number()]).rest(z.boolean()) // [string, number, ...boolean[]]
// Enum
const RoleEnum = z.enum(["admin", "user", "guest"]);
type Role = z.infer<typeof RoleEnum>; // "admin" | "user" | "guest"
// Literal values
z.literal("exact_value")
z.literal(42)
z.literal(true)
// Native TypeScript enum
enum Fruits {
Apple,
Banana,
}
z.nativeEnum(Fruits)
// Enum methods
RoleEnum.enum.admin // "admin"
RoleEnum.exclude(["guest"]) // Exclude values
RoleEnum.extract(["admin", "user"]) // Include only
// Basic union
z.union([z.string(), z.number()])
// Discriminated union (better performance & type inference)
const ResponseSchema = z.discriminatedUnion("status", [
z.object({ status: z.literal("success"), data: z.any() }),
z.object({ status: z.literal("error"), message: z.string() }),
]);
type Response = z.infer<typeof ResponseSchema>;
// { status: "success", data: any } | { status: "error", message: string }
const BaseSchema = z.object({ id: z.string() });
const ExtendedSchema = z.object({ name: z.string() });
const Combined = z.intersection(BaseSchema, ExtendedSchema);
// Equivalent to: z.object({ id: z.string(), name: z.string() })
// Record: object with typed keys and values
z.record(z.string()) // { [key: string]: string }
z.record(z.string(), z.number()) // { [key: string]: number }
// Partial record (some keys optional)
z.partialRecord(z.enum(["a", "b"]), z.string())
// Map
z.map(z.string(), z.number()) // Map<string, number>
z.set(z.string()) // Set<string>
Loadreferences/advanced-patterns.md for complete advanced validation and transformation patterns.
Refinements (custom validation):
z.string().refine((val) => val.length >= 8, "Too short");
z.object({ password, confirmPassword }).superRefine((data, ctx) => { /* ... */ });
Transformations (modify data):
z.string().transform((val) => val.trim());
z.string().pipe(z.coerce.number());
Codecs (bidirectional transforms - NEW in v4.1):
const DateCodec = z.codec(
z.iso.datetime(),
z.date(),
{
decode: (str) => new Date(str),
encode: (date) => date.toISOString(),
}
);
Recursive Types :
const CategorySchema: z.ZodType<Category> = z.lazy(() =>
z.object({ name: z.string(), subcategories: z.array(CategorySchema) })
);
Optional/Nullable :
z.string().optional() // string | undefined
z.string().nullable() // string | null
z.string().default("default") // Provides default if undefined
Readonly & Brand:
z.object({ ... }).readonly() // Readonly properties
z.string().brand<"UserId">() // Nominal typing
→ Loadreferences/advanced-patterns.md for: Complete refinement patterns, async validation, codec examples, composable schemas, conditional validation, performance optimization
Loadreferences/error-handling.md for complete error formatting and customization guide.
Error Formatting Methods :
// For forms
const { fieldErrors } = z.flattenError(error);
// For nested data
const tree = z.treeifyError(error);
const nameError = tree.properties?.user?.properties?.name?.errors?.[0];
// For debugging
console.log(z.prettifyError(error));
Custom Error Messages (three levels):
// 1. Schema-level (highest priority)
z.string({ error: "Custom message" });
z.string().min(5, "Too short");
// 2. Per-parse level
schema.parse(data, { error: (issue) => ({ message: "..." }) });
// 3. Global level
z.config({ customError: (issue) => ({ message: "..." }) });
Localization (40+ languages):
z.config(z.locales.es()); // Spanish
z.config(z.locales.fr()); // French
→ Loadreferences/error-handling.md for: Complete error formatting examples, custom error patterns, localization setup, error code reference
Loadreferences/type-inference.md for complete type inference and metadata documentation.
Basic Type Inference :
const UserSchema = z.object({ name: z.string() });
type User = z.infer<typeof UserSchema>; // { name: string }
Input vs Output (for transforms):
const TransformSchema = z.string().transform((s) => s.length);
type Input = z.input<typeof TransformSchema>; // string
type Output = z.output<typeof TransformSchema>; // number
JSON Schema Conversion :
const jsonSchema = z.toJSONSchema(UserSchema, {
target: "openapi-3.0",
metadata: true,
});
Metadata :
// Add metadata
const EmailSchema = z.string().email().meta({
title: "Email Address",
description: "User's email address",
});
// Create custom registry
const formRegistry = z.registry<FormFieldMeta>();
→ Loadreferences/type-inference.md for: Complete type inference patterns, JSON Schema options, metadata system, custom registries, brand types
Validate function inputs and outputs:
const AddFunction = z.function()
.args(z.number(), z.number()) // Arguments
.returns(z.number()); // Return type
// Implement typed function
const add = AddFunction.implement((a, b) => {
return a + b; // Type-checked!
});
// Async functions
const FetchFunction = z.function()
.args(z.string())
.returns(z.promise(z.object({ data: z.any() })))
.implementAsync(async (url) => {
const response = await fetch(url);
return response.json();
});
const EnvSchema = z.object({
NODE_ENV: z.enum(["development", "production", "test"]),
DATABASE_URL: z.string().url(),
PORT: z.coerce.number().int().positive().default(3000),
API_KEY: z.string().min(32),
});
// Validate on startup
const env = EnvSchema.parse(process.env);
// Now use typed env
console.log(env.PORT); // number
const CreateUserRequest = z.object({
username: z.string().min(3).max(20),
email: z.string().email(),
password: z.string().min(8),
age: z.number().int().positive().optional(),
});
// Express example
app.post("/users", async (req, res) => {
const result = CreateUserRequest.safeParse(req.body);
if (!result.success) {
return res.status(400).json({
errors: z.flattenError(result.error).fieldErrors,
});
}
const user = await createUser(result.data);
res.json(user);
});
const FormSchema = z.object({
firstName: z.string().min(1, "First name required"),
lastName: z.string().min(1, "Last name required"),
email: z.string().email("Invalid email"),
age: z.coerce.number().int().min(18, "Must be 18+"),
agreeToTerms: z.literal(true, {
errorMap: () => ({ message: "Must accept terms" }),
}),
});
type FormData = z.infer<typeof FormSchema>;
const UserSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
});
// For PATCH requests: make everything optional except id
const UpdateUserSchema = UserSchema.partial().required({ id: true });
type UpdateUser = z.infer<typeof UpdateUserSchema>;
// { id: string; name?: string; email?: string }
// Base schemas
const TimestampSchema = z.object({
createdAt: z.date(),
updatedAt: z.date(),
});
const AuthorSchema = z.object({
authorId: z.string(),
authorName: z.string(),
});
// Compose into larger schemas
const PostSchema = z.object({
id: z.string(),
title: z.string(),
content: z.string(),
}).merge(TimestampSchema).merge(AuthorSchema);
Loadreferences/ecosystem-integrations.md for complete framework and tooling integration guide.
ESLint Plugins :
eslint-plugin-zod-x - Enforces best practiceseslint-plugin-import-zod - Enforces import styleFramework Integrations :
react-hook-form-zod skill)Code Generation :
→ Loadreferences/ecosystem-integrations.md for: Setup instructions, integration examples, Hono middleware, Drizzle ORM patterns
Loadreferences/troubleshooting.md for complete troubleshooting guide, performance tips, and best practices.
Common Issues :
tsconfig.jsonz.lazy() for code splittingz.lazy()z.discriminatedUnion().refine() for validation, .transform() for modificationPerformance Tips :
.discriminatedUnion() (5-10x faster than .union()).safeParse() (avoids try-catch overhead)Best Practices :
z.infer).meta()→ Loadreferences/troubleshooting.md for: Detailed solutions, performance optimization, best practices, testing patterns
// Primitives
z.string(), z.number(), z.boolean(), z.date(), z.bigint()
// Collections
z.array(), z.tuple(), z.object(), z.record(), z.map(), z.set()
// Special types
z.enum(), z.union(), z.discriminatedUnion(), z.intersection()
z.literal(), z.any(), z.unknown(), z.never()
// Modifiers
.optional(), .nullable(), .nullish(), .default(), .catch()
.readonly(), .brand()
// Validation
.min(), .max(), .length(), .regex(), .email(), .url(), .uuid()
.refine(), .superRefine()
// Transformation
.transform(), .pipe(), .codec()
// Parsing
.parse(), .safeParse(), .parseAsync(), .safeParseAsync()
// Type inference
z.infer<typeof Schema>, z.input<typeof Schema>, z.output<typeof Schema>
// Error handling
z.flattenError(), z.treeifyError(), z.prettifyError()
// JSON Schema
z.toJSONSchema(schema, options)
// Metadata
.meta(), .describe()
// Object methods
.extend(), .pick(), .omit(), .partial(), .required(), .merge()
Loadreferences/migration-guide.md when:
.merge(), error.format(), etc.)Infinity or unsafe integersLoadreferences/error-handling.md when:
z.flattenError(), z.treeifyError(), or z.prettifyError()Loadreferences/advanced-patterns.md when:
.refine(), .transform(), or .codec()Loadreferences/type-inference.md when:
z.infer, z.input, z.outputLoadreferences/ecosystem-integrations.md when:
Loadreferences/troubleshooting.md when:
.refine() and .transform()Production Notes :
What's New in This Version :
Weekly Installs
157
Repository
GitHub Stars
90
First Seen
Jan 24, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode127
gemini-cli119
github-copilot117
codex117
claude-code114
cursor111
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
116,600 周安装
文本转语音工具 - 使用 inference.sh CLI 实现高品质AI语音合成,支持多种模型和语言
7,800 周安装
Snowflake语义视图助手:自动化创建与验证Snowflake语义视图的AI工具
7,800 周安装
AI代码注释工具 - 为代码文件添加教育性注释,提升学习效率与代码可读性
7,800 周安装
Rust MCP服务器生成器 - 快速创建生产级MCP服务器项目
7,800 周安装
Next.js国际化指南:使用next-intl添加新语言完整教程
7,800 周安装
dotnet-upgrade:AI 辅助 .NET 项目升级与现代化指南,自动化迁移策略
7,800 周安装
z.treeifyError()error.format().implement() method