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

TypeScript中如何将CustomRouteType数组映射为其返回值类型数组?

这个问题我太熟了!你想要的其实就是把数组里的每个构造器/函数类型,转换成它们的返回值类型数组——TypeScript确实没有现成的ReturnValues工具类型,但我们可以自己实现一个映射类型来搞定。

核心思路

我们需要遍历TTypes数组中的每个元素,对每个元素提取它的返回值类型,再重新组成一个新的数组类型。TypeScript的映射类型和ReturnType工具类型可以完美配合完成这个任务。

具体实现步骤

1. 定义数组元素返回值类型的映射类型

首先,我们写一个工具类型InstanceTypes,它接收一个CustomRouteType数组类型,然后返回对应的返回值类型数组:

type InstanceTypes<T extends CustomRouteType[]> = {
  [K in keyof T]: ReturnType<T[K]>;
};

这个类型的作用是:遍历输入数组T的每个索引K,取出该位置的元素类型T[K],用ReturnType获取这个函数类型的返回值,最终组成一个和原数组结构一致的新类型数组。

2. 修改createRoute的类型定义

接下来,把createRoute的回调参数类型从...params: TTypes改成...params: InstanceTypes<TTypes>,这样就能自动把构造器类型映射成对应的返回值类型了:

const createRoute = <TTypes extends CustomRouteType[]>(
  dictionary: RouteDictionary<TTypes>,
  callback: (...params: InstanceTypes<TTypes>) => void
) => {
  // 你的逻辑代码
};

3. 验证效果

现在再调用createRoute时,TypeScript就能正确推断回调参数的类型了:

createRoute(
  route`/api/someEndpoint/${Number}/${String}/test`,
  (p1, p2) => {
    // p1 自动推断为 number 类型
    // p2 自动推断为 string 类型
    const num: number = p1; // ✅ 类型匹配
    const str: string = p2; // ✅ 类型匹配
  }
);

如果是自定义的CustomRouteType,也能正常工作:

// 自定义一个返回boolean的路由参数解析函数
const booleanParam = <T>(value?: T): boolean => !!value;

createRoute(
  route`/api/${booleanParam}`,
  (isValid) => {
    // isValid 自动推断为 boolean 类型
    const flag: boolean = isValid; // ✅ 类型匹配
  }
);

完整修改后的代码

结合你提供的原有代码,完整版本如下:

type CustomRouteType<TParam = any> = <T>(value?: T) => TParam;

class RouteString {
  constructor(public routeString: string) {}
}

class RouteParameter<T = any> {
  constructor(public routeString: CustomRouteType<T>) {}
}

type RouteDictionary<TTypes extends CustomRouteType[]> = {
  routeParts: (RouteString | RouteParameter)[];
  types: TTypes;
};

const route = <TTypes extends CustomRouteType<any>[]>(
  template: TemplateStringsArray,
  ...keys: TTypes
): RouteDictionary<TTypes> => {
  let routeParts: (RouteString | RouteParameter)[] = [];
  const stringParts = template.raw || [];
  for (let partIndex = 0; partIndex < stringParts.length; partIndex++) {
    const part = stringParts[partIndex];
    const stringChunks = part.split('/').filter(chunkPart => chunkPart !== String());
    routeParts = [...routeParts, ...stringChunks.map(chunk => new RouteString(chunk))];
    if (keys.length === 0) continue;
    if (partIndex >= keys.length) continue;
    const routeParam = keys[partIndex];
    if (!routeParam) continue;
    routeParts = [...routeParts, new RouteParameter(routeParam)];
  }
  return { routeParts, types: keys };
};

// 新增的映射类型
type InstanceTypes<T extends CustomRouteType[]> = {
  [K in keyof T]: ReturnType<T[K]>;
};

// 修改后的createRoute
const createRoute = <TTypes extends CustomRouteType[]>(
  dictionary: RouteDictionary<TTypes>,
  callback: (...params: InstanceTypes<TTypes>) => void
) => {
  // 这里可以添加你的逻辑,比如解析路由参数后调用callback
};

// 测试调用
createRoute(
  route`/api/someEndpoint/${Number}/${String}/test`,
  (p1, p2) => {
    console.log(p1.toFixed(2)); // p1是number,支持number的方法
    console.log(p2.toUpperCase()); // p2是string,支持string的方法
  }
);

这个方案的核心就是利用TypeScript的映射类型能力,把数组中的每个函数类型的返回值提取出来,重新组合成新的参数类型数组,完美解决你遇到的类型推断问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:08:10