与其他验证库的比较
Zod 与其他流行的验证库相比有许多独特的优势。
Zod vs Yup
类型推断
ts
// Zod
const userSchema = z.object({
name: z.string(),
age: z.number(),
});
type User = z.infer<typeof userSchema>; // 完美的类型推断
// Yup
const yupSchema = yup.object({
name: yup.string(),
age: yup.number(),
});
// 需要手动定义类型或使用不太精确的推断
默认值处理
ts
// Zod - 明确的默认值处理
const zodSchema = z.object({
name: z.string(),
age: z.number().default(18),
});
// Yup - 更宽松的默认值处理
const yupSchema = yup.object({
name: yup.string(),
age: yup.number().default(18),
});
性能比较
ts
// Zod - 更快的验证速度
const zodResult = userSchema.safeParse(data);
// Yup - 相对较慢
const yupResult = await yupSchema.validate(data);
Zod vs Joi
类型安全
ts
// Zod - 完全类型安全
const zodSchema = z.object({
email: z.string().email(),
age: z.number().min(0),
});
// Joi - 没有内置的类型推断
const joiSchema = Joi.object({
email: Joi.string().email(),
age: Joi.number().min(0),
});
API 风格
ts
// Zod - 链式 API,更现代的语法
const zodSchema = z.string()
.min(3)
.max(20)
.email();
// Joi - 传统的验证 API
const joiSchema = Joi.string()
.min(3)
.max(20)
.email();
Zod vs class-validator
装饰器 vs 模式
ts
// Zod - 声明式模式
const UserSchema = z.object({
@IsEmail()
email: z.string().email(),
@Min(0)
age: z.number().min(0),
});
// class-validator - 基于装饰器
class User {
@IsEmail()
email: string;
@Min(0)
age: number;
}
运行时验证
ts
// Zod - 直接验证
const result = UserSchema.safeParse(data);
// class-validator - 需要实例化
const user = new User();
Object.assign(user, data);
const errors = await validate(user);
Zod 的优势
1. 类型安全
ts
// Zod 自动推断类型
const schema = z.object({
name: z.string(),
age: z.number().optional(),
});
type Person = z.infer<typeof schema>;
// 自动推断为:
// {
// name: string;
// age?: number;
// }
2. 零依赖
ts
// package.json
{
"dependencies": {
"zod": "^3.0.0"
// 不需要其他依赖
}
}
3. 丰富的 API
ts
const schema = z.object({
id: z.string().uuid(),
email: z.string().email(),
website: z.string().url().optional(),
age: z.number().int().min(0).max(120),
birthDate: z.date(),
tags: z.array(z.string()).nonempty(),
});
4. 可扩展性
ts
// 自定义验证器
const passwordSchema = z.string().refine(
(password) => {
// 自定义密码验证逻辑
return password.length >= 8 &&
/[A-Z]/.test(password) &&
/[a-z]/.test(password) &&
/[0-9]/.test(password);
},
{
message: "密码必须包含大小写字母和数字,且长度至少为8",
}
);
5. 转换能力
ts
const schema = z.string()
.transform(s => s.toLowerCase())
.transform(s => s.trim())
.refine(s => s.length > 0, "字符串不能为空");
const result = schema.parse(" HELLO ");
// 结果: "hello"