如何在Express中间件中为req.body分配基于Yup Schema的类型?
为Express Yup验证中间件动态设置req.body类型
你可以通过给验证中间件添加泛型参数,结合Yup的InferType工具类型,实现让req.body自动匹配传入Schema的类型。下面是具体的改造方案:
原问题代码
验证中间件
import { NextFunction, Request, Response } from 'express' import { Schema, ValidationError } from 'yup' export default function validate(schema: Schema) { return async (req: Request, res: Response, next: NextFunction) => { try { const body = await schema.validate(req.body, { stripUnknown: true }) // TODO: Is there a way to dynamically type this to the type of the schema? req.body = body next() } catch (error) { if (error instanceof ValidationError) { return res.status(400).json({ message: error.message }) } return res.status(500).json({ message: 'Unknown error' }) } } }
路由使用示例
import { object, string } from 'yup' // ... const schema = object({ name: string().required() }) app.put('/test/:id', validate(schema), async (req, res) => { // ... req.body.name // 当前类型为any,期望是Schema定义的string类型 req.body.unknownProperty // 期望此处因不属于Schema而报错 // ... })
改造方案
1. 给验证中间件添加泛型支持
修改中间件代码,引入泛型关联Schema类型,通过yup.InferType推导对应TS类型,并扩展Express的Request类型覆盖body字段:
import { NextFunction, Request, Response } from 'express' import { Schema, ValidationError, InferType } from 'yup' // 定义泛型验证函数,T绑定传入的Schema类型 export default function validate<T extends Schema>(schema: T) { // 用泛型Request覆盖body的类型定义 return async (req: Request<{}, {}, InferType<T>>, res: Response, next: NextFunction) => { try { // validate返回的body自动匹配InferType<T>类型 const body = await schema.validate(req.body, { stripUnknown: true }) req.body = body next() } catch (error) { if (error instanceof ValidationError) { return res.status(400).json({ message: error.message }) } return res.status(500).json({ message: 'Unknown error' }) } } }
2. 路由中自动获得类型提示
现在在路由里使用validate(schema)时,TypeScript会自动根据传入的Schema推导req.body的类型:
import { object, string } from 'yup' // ... const schema = object({ name: string().required() }) app.put('/test/:id', validate(schema), async (req, res) => { // req.body.name 类型为 string(符合预期) console.log(req.body.name) // req.body.unknownProperty 会触发TypeScript错误(符合预期) console.log(req.body.unknownProperty) // ... })
原理说明
InferType<T>:Yup提供的工具类型,能从Yup Schema反向推导出对应的TypeScript类型。- 泛型
T extends Schema:确保传入参数是合法的Yup Schema,同时让TypeScript捕获具体的Schema类型。 Request<{}, {}, InferType<T>>:Express的Request类型有三个泛型参数,分别对应params、query、body,这里仅修改第三个参数指定body的类型。
内容的提问来源于stack exchange,提问作者Dennis Martinez
相关产品推荐
相关产品推荐

