TypeScript 数据验证:从理论到实践
在 TypeScript 开发中,一个关键问题在于静态类型检查与来自外部来源(API、表单、localStorage)的实际数据之间存在鸿沟。TypeScript 在编译阶段检查类型,但在运行时类型会消失。数据验证是在运行时检查数据是否符合特定规则的过程,这对应用程序的可靠性至关重要。
本文将介绍 TypeScript 中流行的数据验证库:Zod、Yup、Joi 和 class-validator。我们将探讨它们的特点、使用示例,并帮助您为项目选择合适的工具。
为什么仅靠 TypeScript 不够?
TypeScript 是开发者的工具。它有助于编写更安全的代码,但无法防范:
- 来自 API 的错误数据(例如
age字段可能以字符串"25"形式传入) - 缺少必填字段
- 格式不正确(电子邮件、URL、电话号码)
- 值超出允许范围
运行时数据验证通过检查数据是否符合模式并给出清晰的错误信息来解决这些问题。
Zod —— 现代标准
Zod 是 TypeScript 中最流行的验证库。其主要优势在于与类型系统的紧密集成:可以从模式中自动推断出类型。
安装
npm install zod使用示例
import { z } from 'zod';
// 定义模式const UserSchema = z.object({ id: z.number().positive(), email: z.string().email(), age: z.number().min(18).max(120).optional(), role: z.enum(['admin', 'user', 'guest']),});
// 从模式推断类型type User = z.infer<typeof UserSchema>;
// 验证const result = UserSchema.safeParse({ id: 1, email: 'user@example.com', age: 25, role: 'admin',});
if (result.success) { // result.data —— 类型为 User 的正确数据 console.log(result.data.email);} else { // result.error —— 详细的错误信息 console.log(result.error.format());}Zod 的关键功能:
- 通过
z.infer自动推断类型 - 数据转换(例如,将字符串转换为数字)
- 嵌套对象和数组的验证
- 支持联合类型、交集类型、可区分联合类型
- Refinement —— 自定义检查
Yup —— 久经考验
Yup 是 Formik 作者开发的库。非常适合 React 中的表单验证。Yup 具有更声明式的语法和丰富的生态系统。
示例
import * as yup from 'yup';
const schema = yup.object().shape({ name: yup.string().required('姓名必填'), email: yup.string().email('无效的电子邮件').required(), age: yup.number().positive().integer().min(18, '年龄必须至少为 18'), tags: yup.array().of(yup.string()).min(1, '请至少选择一个标签'),});
schema.validate({ name: 'Ivan', email: 'ivan@example.com', age: 25, tags: ['typescript'],}).then(validData => { console.log('数据有效:', validData);}).catch(err => { console.log('错误:', err.errors);});Yup 的特点:
- 错误消息本地化
- 按需验证(惰性验证)
- 值转换(cast)
- 与 Formik 开箱即用的集成
Joi —— 强大且严格
Joi 是一个拥有大量验证器的库。最初为 Node.js (Hapi.js) 创建,但与 TypeScript 配合使用效果也很好。
<