实战技巧
Express + TypeScript 实战
类型化 Express 路由/中间件、请求体验证、Zod 集成
Express + TypeScript 实战
给 Express 加上 TypeScript——路由参数类型化、请求体验证、中间件类型安全。
学完本章你将: 掌握类型化 Express 路由/中间件、Zod 请求验证。
基础设置
typescript
import express, { Request, Response } from "express";
const app = express();
app.use(express.json());
// 类型化路由处理
app.get("/users/:id", (req: Request<{ id: string }>, res: Response) => {
const userId = req.params.id; // string——类型安全
res.json({ id: userId, name: "小明" });
});
扩展 Request 类型
typescript
// 中间件往 req 上挂数据后,需要扩展类型
declare global {
namespace Express {
interface Request {
user?: { id: number; name: string };
}
}
}
Zod 请求体验证
typescript
import { z } from "zod";
const CreateUserSchema = z.object({
name: z.string().min(2),
email: z.string().email(),
age: z.number().min(0).max(150),
});
type CreateUserInput = z.infer<typeof CreateUserSchema>;
app.post("/users", (req: Request, res: Response) => {
const result = CreateUserSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({ errors: result.error.issues });
}
// result.data 类型是 CreateUserInput
const { name, email, age } = result.data;
// ... 创建用户 ...
});
泛型路由包装
typescript
// 消除样板代码的泛型 handler
type AsyncHandler<P = {}, B = {}> = (
req: Request<P, any, B>,
res: Response
) => Promise<void>;
const asyncHandler = <P = {}, B = {}>(fn: AsyncHandler<P, B>) =>
(req: Request<P, any, B>, res: Response) =>
fn(req, res).catch(err => res.status(500).json({ error: err.message }));
// 使用
app.get("/users", asyncHandler(async (req, res) => {
const users = await db.users.findAll();
res.json(users);
}));