如何在Express+TypeScript+Passport中让中间件后req.user必填?
如何在Express中间件验证后让req.user类型变为必填?
每次编写路由控制器时,都要重复写这段代码:
if (!req.user) return res.status(401).send()
我尝试用Express中间件拦截未登录用户的请求,但遇到了类型标注的问题:Express默认的req.user是可选字段,直接重写全局类型把user设为必填并不合理——毕竟只有经过中间件验证的路由才需要user必填。如果直接给控制器的req参数指定包含必填user的类型,路由会因为类型不匹配报错。请问该怎么解决这个问题?
上下文代码片段
全局Express类型重写
declare global { namespace Express { interface User extends TUser { _id: ObjectId } } }
期望实现的效果
// 路由 router.post('/', sessionMiddleware, controller) // 中间件 const sessionMiddleware = (req: Request, res: Response, next: NextFunction) => { if (!req.user) return res.status(401).send() next() } // 控制器 const controller = (req: RequestWithRequiredUser, res: Response) => { // 此处user的类型不可能为undefined const user = req.user // ...业务逻辑 }
当前实际操作
const controller = (req: Request, res: Response) => { if (!req.user) return res.status(401).send() // ...其他业务逻辑 }
解决方案
方案一:自定义带类型断言的中间件
先定义包含必填user的Request类型,再在中间件验证通过后通过类型断言转换req的类型:
// 定义带必填user的Request类型 type RequestWithRequiredUser = Express.Request & { user: Express.User; }; // 认证中间件 const requireAuth = (req: Express.Request, res: Express.Response, next: Express.NextFunction) => { if (!req.user) { return res.status(401).send(); } // 类型断言,告知TypeScript此时req.user已存在 next(null, req as RequestWithRequiredUser); }; // 路由使用示例 router.post('/', requireAuth, (req: RequestWithRequiredUser, res) => { // 此处req.user类型为必填,不会提示undefined console.log(req.user._id); });
方案二:使用类型守卫函数
写一个类型守卫函数,在控制器里快速验证并缩小req的类型范围:
// 定义带必填user的Request类型 type RequestWithRequiredUser = Express.Request & { user: Express.User; }; // 类型守卫函数 function hasRequiredUser(req: Express.Request): req is RequestWithRequiredUser { return req.user !== undefined; } // 控制器中使用 const controller = (req: Express.Request, res: Express.Response) => { if (!hasRequiredUser(req)) { return res.status(401).send(); } // 此处req.user自动推断为必填类型 console.log(req.user._id); };
方案三:类型绑定的中间件(更优雅)
通过类型声明合并,让中间件后续的路由处理函数自动获得正确的类型:
// 定义带必填user的Request类型 type RequestWithRequiredUser = Express.Request & { user: Express.User; }; // 给中间件添加类型,确保后续处理函数的req类型正确 const requireAuth: Express.RequestHandler = (req, res, next) => { if (!req.user) { return res.status(401).send(); } next(); } as unknown as ( req: Express.Request, res: Express.Response, next: (err?: any) => void ) => void; // 路由使用时,控制器的req自动推断为RequestWithRequiredUser router.post('/', requireAuth, (req, res) => { console.log(req.user._id); // 无类型提示问题 });
内容的提问来源于stack exchange,提问作者Luna
相关产品推荐
相关产品推荐

