TypeScript 的类型在编译后完全消失,运行时 incoming 数据(API 请求、表单输入、环境变量)可能是任意值。Zod 是在 TypeScript 生态中最流行的运行时类型验证库——它与 TS 类型系统天然配合,用声明式的方式定义数据schema,并自动推断出对应的 TS 类型。
一、Zod 基础
npm install zod
import { z } from 'zod';
// 定义 schema
const UserSchema = z.object({
id: z.number(),
name: z.string().min(1).max(100),
email: z.string().email(),
age: z.number().int().min(0).optional(),
role: z.enum(['user', 'admin']),
});
// 自动推断 TypeScript 类型
type User = z.infer<typeof UserSchema>;
// 等同于:
// type User = { id: number; name: string; email: string; age?: number; role: 'user' | 'admin' }
// 运行时验证
const result = UserSchema.safeParse(unknownData);
if (!result.success) {
console.log(result.error.issues); // 详细的验证错误
} else {
const user: User = result.data;
}
二、API 请求验证
// Express 中间件
import { Request, Response, NextFunction } from 'express';
import { z, ZodError } from 'zod';
const CreatePostSchema = z.object({
title: z.string().min(1).max(200),
content: z.string().min(1),
tags: z.array(z.string()).max(10),
});
function validateBody<T extends z.ZodType>(schema: T) {
return (req: Request, res: Response, next: NextFunction) => {
const result = schema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({
error: 'Validation failed',
details: result.error.issues,
});
}
req.body = result.data;
next();
};
}
app.post('/posts', validateBody(CreatePostSchema), (req, res) => {
// req.body 已验证为 CreatePost 类型
const { title, content, tags } = req.body;
// ...
});
三、环境变量类型安全
// env.ts
import { z } from 'zod';
const envSchema = z.object({
NODE_ENV: z.enum(['development', 'production', 'test']),
PORT: z.string().transform(Number).default('3000'),
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
REDIS_URL: z.string().url().optional(),
});
export const env = envSchema.parse(process.env);
// 如果缺少必需变量或格式错误,启动时直接抛出清晰的错误
四、React Hook Form + Zod
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
email: z.string().email('请输入有效的邮箱'),
password: z.string().min(8, '密码至少8位'),
});
type FormData = z.infer<typeof schema>;
function LoginForm() {
const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
resolver: zodResolver(schema),
});
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<input {...register('email')} />
{errors.email && <span>{errors.email.message}</span>}
<input type="password" {...register('password')} />
<button type="submit">登录</button>
</form>
);
}
相关阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。
「frontend」更多文章
Vue 性能优化指南:虚拟列表、懒加载、渲染优化与 Core Web Vitals
Vue 3 应用性能优化完整策略:虚拟滚动(vue-virtual-scroller)、组件懒加载与异步组件、KeepAlive 缓存、Suspense 异步优化、v-memo 渲染记忆化、响应式性能(shallowRef/toRaw)、Bundle 分析与代码分割、渲染函数优化、以及 Core Web Vitals(LCP/INP/CLS)调优。
Nuxt.js 完全指南:Vue 全栈框架的 SSR、SSG、API 路由与部署实践
Nuxt.js 3 深度实践:文件系统路由、SSR/SSG/ISR 渲染模式、API 路由(Server Routes)、useFetch/useAsyncData 数据获取、中间件与插件、SEO 与 Meta 管理、Nitro 服务端引擎、自动导入、部署到 Vercel/Netlify/Node.js。
Vue 测试深度指南:Vitest + Vue Test Utils + Playwright E2E 与 CI 集成
Vue 3 应用从单元测试到 E2E 的完整测试策略:Vitest + Vue Test Utils 组件测试(mount/emits/slots/async)、Pinia Store Mocking、MSW API 拦截、Playwright 端到端测试、Cypress 组件测试、覆盖率标准与 GitHub Actions CI 集成。