You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Express+TypeScript中间件报错:'void'无法赋值给'PathParams'

解决Express+TypeScript全局中间件类型不匹配问题

问题场景

我是TypeScript新手,正在将现有JavaScript应用迁移到TS。编写了一个Express全局请求日志中间件:

const { logger } = require("winston"); 
import express, { Application, Request, Response, NextFunction } from 'express'
// ...
const app: Application = express();
// ...
// Middleware - Log all http requests
app.use((req: Request, res: Response, next: NextFunction) => {
  logger.info(`${req.loggedInUser} user [${req.originalUrl}]`) ;
  return next();
});

编译报错信息

The last overload gave the following error.
    Argument of type '(req: Request, res: Response, next: NextFunction) => void' is not assignable to parameter of type 'PathParams'.

已做的尝试

我已在index.d.ts中扩展了Request对象:

declare module "express" { 
  export interface Request {
    user: any;
    loggedInUser: any;
    oidc: any;
  }
}

同时尝试了以下无效方法:

  • 为函数设置返回类型void;
  • 为中间件添加as express.RequestHandler断言;
  • 将Request改为any类型(可运行但不规范);
  • 添加路径参数'/'(IDE无报错但编译失败)。

解决方案及原理

核心问题分析

报错本质是TypeScript无法正确识别中间件函数的类型,导致错误匹配app.use()的重载(误将中间件函数当作PathParams类型处理)。主要原因有三点:

  1. 自定义的Express类型扩展未被TypeScript正确加载;
  2. 混合使用CommonJS(require)和ES模块(import)语法,干扰了类型推断;
  3. 手动指定req/res/next的类型,反而让TS无法正确推导RequestHandler类型。

具体解决步骤

  1. 统一模块语法
    将winston的导入改为ES模块格式,避免混合加载:

    import { logger } from 'winston';
    
  2. 确保自定义类型被加载

    • 确认index.d.ts放在src目录下,或在tsconfig.json的include数组中包含该文件:
      {
        "include": ["src/**/*", "index.d.ts"]
      }
      
    • 检查tsconfig.json的compilerOptions.typeRoots,确保包含自定义类型目录(如果有):
      {
        "compilerOptions": {
          "typeRoots": ["./node_modules/@types", "./src/types"]
        }
      }
      
  3. 正确标注中间件类型
    直接使用RequestHandler类型定义中间件,让TS自动推导参数类型:

    import express, { Application, RequestHandler } from 'express';
    
    // ...
    
    const requestLogger: RequestHandler = (req, res, next) => {
      logger.info(`${req.loggedInUser} user [${req.originalUrl}]`);
      next();
    };
    
    app.use(requestLogger);
    

    或者使用类型断言时确保类型引用正确:

    app.use((req, res, next) => {
      logger.info(`${req.loggedInUser} user [${req.originalUrl}]`);
      next();
    } as RequestHandler);
    

原理说明

Express的app.use()提供了多个重载:

  • 重载1:接收路径参数 + 中间件函数;
  • 重载2:直接接收RequestHandler类型的中间件函数。

当TS无法正确识别中间件的RequestHandler类型时,会尝试匹配最后一个重载(路径相关的重载),从而抛出“无法赋值给PathParams”的错误。通过统一模块语法、确保自定义类型加载、正确使用RequestHandler类型,可以让TS匹配到正确的重载,解决类型不匹配问题。

内容的提问来源于stack exchange,提问作者Jessvin Thomas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 04:36:13