Zod 入门指南:用最简单的方式理解 TypeScript 数据验证利器

24 阅读4分钟

Zod 是一个专为 TypeScript 设计的“模式声明和数据验证”库。它能帮你定义数据结构规则(Schema),并在程序运行时检查数据是否符合这些规则,保证数据安全且类型正确。最棒的是,你只需写一遍规则,Zod 就会帮你自动生成对应的 TypeScript 类型,实现编译时和运行时的双重保护。


1. Zod 是什么?

  • 模式声明(Schema) :用来描述数据的形状和类型,比如字符串、数字、对象结构等。
  • 运行时验证:Zod 会检查实际数据是否符合你定义的模式。
  • 自动类型推断:通过 z.infer,Zod 自动生成对应的 TypeScript 类型,避免重复写类型声明。
  • 零依赖且体积小:压缩后只有约8KB,适合浏览器和 Node.js 环境。

2. Zod 的核心功能

2.1 基本类型验证

Zod 支持字符串、数字、布尔值、日期等多种基本类型验证。

import { z } from "zod";

const stringSchema = z.string();
stringSchema.parse("hello"); // 通过验证,返回 "hello"
stringSchema.parse(123);     // 抛出错误,类型不匹配

const numberSchema = z.number();
numberSchema.parse(42);      // 通过验证
numberSchema.parse("42");    // 抛出错误

2.2 对象结构验证

定义对象的字段和类型,支持设置字段规则(如最小长度、最小值等)。

const userSchema = z.object({
  name: z.string().min(3, "名字至少3个字符"),
  age: z.number().min(18, "年龄必须至少18岁"),
});

const validUser = { name: "小明", age: 20 };
userSchema.parse(validUser); // 通过验证

const invalidUser = { name: "小", age: 16 };
userSchema.parse(invalidUser); // 抛出错误,name和age不符合规则

2.3 数组验证

验证数组中每个元素的类型。

const numberArray = z.array(z.number());
numberArray.parse([1, 2, 3]);       // 通过验证
numberArray.parse([1, "2", 3]);     // 抛出错误,数组中有字符串

2.4 联合类型和枚举验证

验证数据是否属于多个类型之一,或是否是枚举中的一个值。

const roleSchema = z.enum(["Admin", "User", "Guest"]);
roleSchema.parse("Admin");       // 通过验证
roleSchema.parse("SuperAdmin");  // 抛出错误

// 联合类型示例
const unionSchema = z.union([z.string(), z.number()]);
unionSchema.parse("hello"); // 通过
unionSchema.parse(123);     // 通过
unionSchema.parse(true);    // 抛出错误

2.5 自定义验证

使用 .refine().superRefine() 方法添加复杂的自定义规则。

const phoneSchema = z.object({
  phone: z.string(),
  confirmPhone: z.string(),
}).refine(data => data.phone === data.confirmPhone, {
  message: "手机号和确认手机号必须一致",
});

phoneSchema.parse({ phone: "1234567890", confirmPhone: "1234567890" }); // 通过
phoneSchema.parse({ phone: "123", confirmPhone: "456" });             // 抛出错误

2.6 安全解析 .safeParse()

避免抛异常,返回验证结果对象,方便统一处理错误。

const result = z.string().safeParse(123);
if (!result.success) {
  console.log(result.error.errors); // 打印详细错误信息
}

3. Zod 的使用场景举例

3.1 API 请求数据验证

确保前端发送到后端的数据格式正确,避免业务逻辑错误。

const requestSchema = z.object({
  id: z.string(),
  limit: z.number().optional(),
});

const requestData = { id: "abc123", limit: 10 };
requestSchema.parse(requestData); // 通过验证

3.2 表单数据验证

前端或后端验证用户输入,保证数据安全和用户体验。

const formSchema = z.object({
  username: z.string().min(1, "用户名不能为空"),
  email: z.string().email("邮箱格式不正确"),
});

try {
  formSchema.parse({ username: "张三", email: "not-an-email" });
} catch (e) {
  console.error(e.errors); // 输出邮箱格式错误信息
}

3.3 环境变量验证

启动时验证环境变量,避免配置错误导致程序异常。

const envSchema = z.object({
  NODE_ENV: z.enum(["development", "production", "test"]),
  PORT: z.string().transform(val => parseInt(val, 10)),
});

const env = envSchema.parse(process.env);
console.log(env.PORT); // 确保 PORT 是数字类型

4. Zod 解决了哪些问题?

  • 运行时类型缺失:TypeScript 只能编译时检查,Zod 补充运行时验证,保证数据安全。
  • 减少重复声明:类型和验证规则写一处,自动推断类型,避免不一致。
  • 简化复杂数据校验:链式调用轻松定义复杂嵌套结构。
  • 统一错误处理.safeParse() 提供统一接口,方便捕获和处理错误。

5. 进阶示例:完整用户注册验证

import { z } from "zod";

const userSchema = z.object({
  username: z.string().min(3, "用户名至少3个字符"),
  password: z.string().min(6, "密码至少6位"),
  email: z.string().email("无效的邮箱格式"),
  birthDate: z.date().max(new Date(), "生日不能晚于今天"),
  role: z.enum(["Admin", "User", "Guest"]),
});

type User = z.infer<typeof userSchema>;

const userInput = {
  username: "张三",
  password: "123456",
  email: "zhangsan@example.com",
  birthDate: new Date("1990-01-01"),
  role: "User",
};

try {
  const user: User = userSchema.parse(userInput);
  console.log("验证通过,用户数据:", user);
} catch (e) {
  console.error("验证失败:", e.errors);
}

6. 总结

Zod 是 TypeScript 项目中非常实用的工具,帮助你:

  • 简单快速地定义数据结构和验证规则
  • 自动推断类型,减少重复代码
  • 运行时保证数据安全,避免异常和错误
  • 支持丰富的类型和自定义验证,满足各种复杂场景

无论是前端表单、后端 API,还是环境配置,Zod 都能让你的代码更健壮、更易维护。


通过以上介绍和示例,你可以快速上手 Zod,提升你的 TypeScript 开发体验和代码质量。