引言💭
在学习react过程中接触了一下zod,这篇文章来深入了解一下什么是zod。
一、Zod 是什么?
Zod 是一个 TypeScript 优先的模式验证库,用于在运行时验证和解析数据结构,确保数据类型安全。
这是官网中给的例子:
typescript
import { z } from "zod/v4";
// 定义 Schema(模式)
// 这里定义了一个名为 User 的 Schema,它表示一个对象,
// 其中必须包含一个 name 属性,且 name 必须是字符串类型(z.string())。
const User = z.object({
name: z.string(),
});
// 待验证的数据
// input 是一个未知的、可能不受信任的数据(比如来自 API 响应、用户输入等),
// 需要验证是否符合 User Schema。
const input = { /* stuff */ };
// 解析和验证数据
// User.parse(input) 会检查 input 是否符合 User Schema:
// 如果符合,返回解析后的数据(类型安全,TypeScript 会推断 data 的类型为 { name: string })。
// 如果不符合,Zod 会抛出一个错误(ZodError)。
const data = User.parse(input);
// 由于 data 已经通过 Zod 验证,可以放心使用 data.name,因为它一定是 string 类型。
console.log(data.name);
Zod 的核心思想是:
定义模式(schema) → 推导类型 → 验证数据
特征
- 零外部依赖
- 适用于 Node.js 和所有现代浏览器
- 微小:2kb 核心包(gzip 压缩)
- 不可变 API:方法返回一个新实例
- 简洁的界面
- 适用于 TypeScript 和纯 JS
- 内置 JSON Schema 转换
- 广泛的生态系统
基本用法
建议查阅官方文档,这里不作过多赘述。
看到这里是不是有种熟悉的感觉,这不是老朋友interface吗?
二、Zod Schema和Interface
Zod Schema
和 TypeScript 的 interface
确实在结构上很相似,它们都用来定义对象的"形状"和"属性"。但它们的用途、时机和能力有明显区别:
🧩 1. 编译时 vs 运行时
比较项 | interface | Zod Schema |
---|---|---|
类型检查时机 | 编译时(开发时) | 运行时 |
作用 | 提供类型提示、静态检查 | 对传入数据进行实际的运行时校验 |
能否在运行时使用 | 会被擦除 | 运行时可判断是否合法 |
🔍 2. 示例对比
interface
示例(仅开发时检查
typescript
interface User {
name: string;
age: number;
}
function greet(user: User) {
console.log(`Hello, ${user.name}`);
}
// 编译时能检查,但运行时不会验证结构
Zod
示例(运行时校验)
javascript
import { z } from "zod";
const UserSchema = z.object({
name: z.string(),
age: z.number(),
});
function greet(user: unknown) {
const parsed = UserSchema.parse(user); // 若不合法会抛错
console.log(`Hello, ${parsed.name}`);
}
🧠 3. 用途对比
用途 | interface | Zod |
---|---|---|
类型提示 | ✅ | ❌(需通过 .infer 获取类型) |
运行时输入验证(API、表单) | ❌ | ✅ |
提供 IDE 自动补全 | ✅ | ❌(Zod Schema 可反推出类型) |
数据转换(默认值、类型转换) | ❌ | ✅(Zod 提供 .transform() ) |
🔁 4. 配合使用
最佳实践 是 Zod + TypeScript 联用:
ini
const UserSchema = z.object({
name: z.string(),
age: z.number(),
});
type User = z.infer<typeof UserSchema>; // 自动提取类型
这样既能进行运行时校验 ,又能享受类型推导带来的开发体验。
总结一句话
interface
是开发阶段的类型说明,Zod
是运行阶段的数据验证器。它们可以配合使用,各司其职。
三、在 React 项目中的使用
1. 验证表单数据
Zod 可以用来验证用户在表单中输入的数据,搭配 react-hook-form
特别方便。
示例:表单验证
tsx
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import {z} from "zod";
// 定义 Zod 验证 schema(运行时验证规则)
const schema = z.object({
name: z.string().min(2, "名字至少2个字符"),
age: z.number().min(18, "必须年满18岁"),
});
// 使用 z.infer 推导出 schema 对应的 TypeScript 类型
type FormData = z.infer<typeof schema>;
export default function MyForm() {
// 初始化表单,使用 useForm
const {
register, // 注册表单字段,连接 input 元素和 React Hook Form
handleSubmit,
formState: { errors },
} = useForm<FormData>({
resolver: zodResolver(schema), // 指定使用 zodResolver(schema),让 Zod 参与验证
});
// 提交处理函数,只有通过验证时才会调用
const onSubmit = (data: FormData) => {
console.log(data);
};
return (
// handleSubmit(onSubmit)会拦截提交事件:
// 验证失败 → 不提交;验证成功 → 调用 onSubmit
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name")} placeholder="名字" />
<!--- 如果errors.name存在则显示message:"名字至少2个字符",不存在则不显示-->
{errors.name && <p>{errors.name.message}</p>}
<input type="number" {...register("age", { valueAsNumber: true })} placeholder="年龄" />
<!--如果errors.age存在则显示message:"必须年满18岁",不存在则不显示-->
{errors.age && <p>{errors.age.message}</p>}
<button type="submit">提交</button>
</form>
);
}
2. 校验 API 返回的数据
例如,fetch 后对返回结果进行类型和结构的校验:
tsx
const userSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
});
fetch("/api/user")
.then(res => res.json())
.then(data => {
// 使用 Zod 的 safeParse 进行安全校验
// 返回的是一个包含 success 和 data/error 的对象
const result = userSchema.safeParse(data);
if (result.success) {
// 校验成功,result.data 是类型安全的对象
console.log(result.data);
} else {
// 校验失败,result.error 是详细的验证错误信息
console.error("数据结构不符合预期", result.error);
}
});
3. 组件 props 验证(开发阶段)
虽然 TypeScript 已经能检查 props 类型,但你可以使用 Zod 在运行时对 props 进行额外校验(比如防止外部调用者传错结构)。
tsx
import React from "react";
import {z} from "zod";
// 定义 props 的 schema
const userCardPropsSchema = z.object({
name: z.string(),
age: z.number().int().min(0),
});
type UserCardProps = z.infer<typeof userCardPropsSchema>;
// 定义函数组件,并使用推导出来的 props 类型
export const UserCard: React.FC<UserCardProps> = (props) => {
// 使用 Zod 的 safeParse 方法在运行时校验 props 的合法性
const result = userCardPropsSchema.safeParse(props);
if (!result.success) {
// 校验失败,打印错误信息,避免渲染非法数据
console.error("UserCard props 验证失败:", result.error);
return <div>传入的 props 不合法</div>;
}
// 解构通过验证的数据,类型安全
const { name, age } = result.data;
// 正常渲染组件内容
return (
<div>
<h2>{name}</h2>
<p>年龄: {age}</p>
</div>
);
};
四、Zod 的优势(特别适用于 React)
优点 | 描述 |
---|---|
类型推导 | 使用 z.infer 可以自动获得类型定义 |
TypeScript 友好 | 完美支持 TS,无需重复定义类型 |
表单库兼容性 | 和 react-hook-form 等库配合默契 |
可组合性强 | 支持嵌套 schema、交叉验证、联合类型等 |
运行时验证 | 提供真实的运行时类型检查(TS 在编译时) |
五、与其他库的比较(Yup, Joi)
特性 | Zod | Yup | Joi |
---|---|---|---|
TypeScript 支持 | ✅ 极好 | ⚠️ 一般 | ❌ 较差 |
学习曲线 | 简单 | 稍复杂 | 较复杂 |
表单支持 | ✅ react-hook-form 优先支持 | ✅ | ❌ |
Schema 推导 | ✅ 自动推导 | ❌ 需手动 | ❌ 需手动 |
结语✒️
知识点+1✨✨✨
