Z
ZHANK
编程在线教程TypeScript 教程Express + TypeScript 实战
实战技巧

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);
}));