如何将 TypeScript 类型守卫与 Zod 数据验证结合使用?
摘要:我见过许多因为运行时数据不匹配而导致的崩溃,也曾写过无数防御性代码和 any 断言,哈哈 😄。TypeScript 的类型安全本来就不该止步于编译期。直到遇见 Zod,Zod 不仅是一个验证库,它为 Type
我见过许多因为运行时数据不匹配而导致的崩溃,也曾写过无数防御性代码和 any 断言,哈哈 😄。TypeScript 的类型安全本来就不该止步于编译期。直到遇见 Zod,Zod 不仅是一个验证库,它为 TypeScript 带来运行时安全,是目前最优雅、最彻底的解决方案。
我们为何需要 Zod?
TypeScript 最让人上瘾的地方在于编译时类型检查,但这也是它的最大谎言,因为类型在运行时彻底消失,你需要小心小心再小心,使用 TypeScript 并不代表类型安全。
interface User {
name: string;
age: number;
role: 'admin' | 'user';
}
fetch('/api/user').then(res => res.json()).then((data: User) => {
// 编译通过,但如果 data.role 返回的是 "administrator",运行会报错
console.log(data.role.toUpperCase());
});
而 Zod 的答案是:只定义一次 Schema,既得到运行时验证,又得到完美的 TypeScript 类型。
const UserSchema = z.object({
name: z.string(),
age: z.number(),
role: z.enum(['admin', 'user']),
});
type User = z.infer<typeof UserSchema>;
通过 Schema 推断出完美类型 User,无需二次声明。这样, UserSchema 用于运行时验证,User 用于类型推断。
Zod 入门
npm install zod
import { z } from 'zod';
// 基础类型
const StringSchema = z.string();
const NumberSchema = z.number().int().positive();
核心 API:parse 和 safeParse,我建议优先使用 .safeParse()。
const schema = z.string();
try {
const result = schema.parse(123);
console.log(result);
} catch (error) {
console.error('验证失败:', error.errors);
}
parse 抛出 ZodError, 你需要通过 try catch 捕获错误,否则导致程序崩溃。
const schema = z.string();
const result = schema.safeParse(123);
if (result.success) {
console.log('验证成功:', result.data);
} else {
console.log('验证失败:', result.error.errors);
}
safeParse 返回 { success: true, data: T } 或 { success: false, error: ZodError },你可以通过 success 判断是否验证成功,然后通过 data 获取验证后的数据,或者通过 error.errors 获取错误信息, 这样你可以优雅地处理错误。
