如何为Express的已认证/未认证请求定义TypeScript类型?
解决TypeScript识别Express已认证路由请求类型的方案
方案1:定义已认证专用请求接口 + 类型守卫
首先在全局声明文件中扩展两个接口:一个适配所有路由的基础Request(user可空),另一个是保证user非空的已认证专用接口:
// types/express.d.ts declare global { namespace Express { // 基础请求接口,覆盖所有路由场景 interface Request { isAuthenticated: boolean; sid?: string; locals: { user: User | null; }; } // 已认证请求专用接口,强制user非null interface AuthenticatedRequest extends Request { locals: { user: User; }; } } } // 导出空对象让TypeScript识别为模块 export {};
接着编写认证中间件,用类型守卫函数判断请求是否符合已认证状态,未认证直接拦截:
// middleware/auth.ts import { Request, Response, NextFunction } from 'express'; // 类型守卫:校验请求是否为已认证状态 function isAuthenticated(req: Request): req is Express.AuthenticatedRequest { return req.isAuthenticated === true && req.locals.user !== null; } // 强制认证中间件 export const requireAuth = (req: Request, res: Response, next: NextFunction) => { if (!isAuthenticated(req)) { return res.status(401).send('未授权,请先登录'); } // 经过守卫后,后续路由的req会被TypeScript自动推断为AuthenticatedRequest next(); };
在路由中使用该中间件后,无需重复判断user是否存在,TypeScript会自动识别user的非空状态:
// routes/profile.ts import { Router } from 'express'; import { requireAuth } from '../middleware/auth'; const router = Router(); router.get('/me', requireAuth, (req, res) => { // TypeScript 自动推断 req 为 AuthenticatedRequest,user 非null res.json({ id: req.locals.user.id, username: req.locals.user.username }); });
方案2:中间件内直接类型断言(简化版)
如果觉得类型守卫过于繁琐,可在认证中间件里直接用类型断言,但要确保中间件已经拦截了所有未认证请求:
// middleware/auth.ts export const requireAuth = (req: Request, res: Response, next: NextFunction) => { if (!req.isAuthenticated || req.locals.user === null) { return res.status(401).send('未授权'); } // 断言为已认证请求类型,后续路由可直接使用 next(); }; // 路由中使用时,可手动指定类型或让TypeScript自动推断 router.get('/settings', requireAuth, (req: Express.AuthenticatedRequest, res) => { res.json({ email: req.locals.user.email }); });
核心思路
- 基础Request接口保留
user | null的宽松类型,适配所有路由场景; - 专用的
AuthenticatedRequest接口确保user非空,仅用于经过认证中间件的路由; - 通过类型守卫或中间件拦截,让TypeScript自动推断请求类型,彻底消除重复的
if (user)判断。
内容的提问来源于stack exchange,提问作者Storm
相关产品推荐
相关产品推荐

