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

TypeScript如何从参数推断Express回调的泛型类型

解决方案

核心原因

你当前的泛型参数都设置了默认值,TypeScript 推断类型时会优先填充默认值,不会等待从 app.get 的路由路径上下文获取具体的参数类型,因此 req.params 会被推断为通用的 ParamsDictionary(带任意字符串索引签名),自然不会有参数名的类型校验。

最优修复方案

移除首个泛型参数 P 的默认值,强制 TypeScript 从外层上下文推断类型,不需要额外修改调用逻辑:

import { RequestHandler, ParamsDictionary, ParsedQs } from "express";

function tryCatchNext<
  // 移除P的默认值,强制从上下文推断
  P extends ParamsDictionary,
  ResBody = any,
  ReqBody = any,
  ReqQuery extends ParsedQs = ParsedQs,
  Locals extends Record<string, any> = Record<string, any>
>(
  callback: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>
): RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals> {
  return async (req, res, next) => {
    try {
      await callback(req, res, next);
    } catch (err) {
      next(err);
    }
  };
}

修改后直接按你原来的方式调用即可,req.params 会自动从路由路径中推断出存在的字段:

app.get('/:foo', tryCatchNext(async (req, res, next) => {
  // 正常识别foo参数
  if (req.params.foo === 'bar') {
    throw new Error('That was a bar.');
  }

  // 此处会触发类型错误,符合预期
  console.log(req.params.bar);

  res.send('Not a bar');
}));

兼容无上下文场景的方案

如果你需要在没有外层上下文的地方使用 tryCatchNext,可以用函数重载同时支持两种场景:

import { RequestHandler, ParamsDictionary, ParsedQs } from "express";

// 重载1:有上下文可推断的场景,不需要传泛型
function tryCatchNext<
  P extends ParamsDictionary,
  ResBody = any,
  ReqBody = any,
  ReqQuery extends ParsedQs = ParsedQs,
  Locals extends Record<string, any> = Record<string, any>
>(
  callback: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>
): RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>;

// 重载2:无上下文的场景,使用默认泛型
function tryCatchNext(
  callback: RequestHandler
): RequestHandler;

// 实现
function tryCatchNext(
  callback: RequestHandler
): RequestHandler {
  return async (req, res, next) => {
    try {
      await callback(req, res, next);
    } catch (err) {
      next(err);
    }
  };
}

轻量替代方案

如果不想修改工具函数定义,也可以在调用时直接给回调的 req 参数标注类型:

import { Request } from "express";

app.get('/:foo', tryCatchNext(async (req: Request<{foo: string}>, res, next) => {
  // 同样可以获得正确的类型校验
}));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 10:42:00