首页
/ ts-rest项目中Express中间件类型化问题的解决方案

ts-rest项目中Express中间件类型化问题的解决方案

2025-06-28 22:16:30作者:柏廷章Berta

在使用ts-rest框架时,开发者可能会遇到Express中间件在类型化场景下不触发的问题。本文将深入分析这一问题的根源,并提供有效的解决方案。

问题现象

在ts-rest项目中,当尝试使用泛型类型参数创建可复用的中间件时,中间件可能不会按预期执行。具体表现为:

  1. 使用泛型方式定义的中间件(adminOnlyMiddleware<T>())不会被调用
  2. 直接在路由中定义的相同逻辑中间件却能正常工作

问题分析

造成这一现象的根本原因在于Express中间件的类型系统与ts-rest的类型推断机制之间的交互方式。当使用高阶函数返回中间件时(即函数返回函数),Express可能无法正确识别并调用内部的中间件函数。

解决方案

推荐方案:直接函数定义

将中间件定义为普通函数而非高阶函数,可以确保Express正确识别并调用:

function checkAuthorization<T>(req: T, res: Response, next: NextFunction) {
  const roles = [USER_ROLE.ADMIN.valueOf(), USER_ROLE.SUPER_ADMIN.valueOf()];
  // @ts-ignore
  if (roles.includes(req.auth.role)) {
    return next();
  } else {
    return res.status(401).json({ message: "Unauthorized" });
  }
};

替代方案:类型断言

如果必须使用高阶函数形式,可以通过类型断言确保类型正确:

const adminOnlyMiddleware = <T>() => {
    return (req: T, res: Response, next: NextFunction) => {
        // 实现逻辑
    } as RequestHandler;
};

最佳实践建议

  1. 优先使用简单函数:在大多数情况下,直接定义的函数比高阶函数更可靠
  2. 明确类型定义:为中间件参数提供清晰类型,避免使用@ts-ignore
  3. 考虑请求扩展:可以扩展Express的Request类型以包含自定义属性如auth

类型安全改进

为了完全避免使用@ts-ignore,可以扩展Express的Request类型:

declare global {
  namespace Express {
    interface Request {
      auth: {
        role: string;
      };
    }
  }
}

这样中间件可以完全类型安全地编写:

function checkAuthorization(req: Request, res: Response, next: NextFunction) {
  const roles = [USER_ROLE.ADMIN, USER_ROLE.SUPER_ADMIN];
  if (roles.includes(req.auth.role)) {
    return next();
  }
  return res.status(401).json({ message: "Unauthorized" });
};

通过理解这些模式,开发者可以在ts-rest项目中更安全、更可靠地实现类型化的Express中间件。

登录后查看全文
热门项目推荐
相关项目推荐