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

推导关联函数数组的类型:参数转换后的返回类型定义

解决思路:用TypeScript映射类型+ReturnType提取返回类型

看起来你想要的是一个能转换函数对象中所有函数参数类型、同时保留键名和返回类型的工具,对吧?你的初始尝试方向是对的,但泛型的用法需要调整——因为你需要保留每个函数独有的返回类型,而不是让所有函数共享一个泛型返回类型。

核心问题分析

你的初始定义type FunctionMap<A> = { [functionName: string]: <R>(a: A) => R }存在两个关键问题:

  • 函数级别的泛型<R>意味着每次调用函数都可以随意指定返回类型,而非固定原函数的固有返回类型
  • 所有函数的返回类型被统一定义为任意的R,丢失了每个函数独有的类型信息

步骤1:定义转换后的函数对象类型

我们可以写一个泛型类型TransformedFunctionMap,它会遍历输入对象的每个键,单独处理每个函数的类型:

// 约束输入必须是键为字符串、值为函数的对象
type TransformedFunctionMap<T extends Record<string, (...args: any[]) => any>, NewParams> = {
  [K in keyof T]: (params: NewParams) => ReturnType<T[K]>
};

这里ReturnType<T[K]>是TypeScript内置工具类型,专门用来提取函数T[K]的返回类型,能完美保留原函数的返回类型信息。

步骤2:实现转换函数

接下来写一个工具函数,把输入的函数对象转换成目标类型。如果需要在新参数和原参数之间做格式转换(比如把B转成原函数需要的A),可以加一个可选的参数转换函数:

function transformFunctionMap<
  T extends Record<string, (...args: any[]) => any>,
  NewParams,
  OriginalParams = Parameters<T[keyof T]>[0]
>(
  funcMap: T,
  // 可选:把新参数转换成原函数需要的参数的转换逻辑
  convertParams?: (newParams: NewParams) => OriginalParams
): TransformedFunctionMap<T, NewParams> {
  const result = {} as TransformedFunctionMap<T, NewParams>;

  // 遍历每个函数,包装成接收新参数的函数
  for (const key in funcMap) {
    if (Object.prototype.hasOwnProperty.call(funcMap, key)) {
      result[key] = (newParams: NewParams) => {
        // 如果有转换函数,先转换参数;否则直接传入(需确保类型兼容)
        const originalArgs = convertParams ? [convertParams(newParams)] : [newParams as OriginalParams];
        return funcMap[key](...originalArgs);
      };
    }
  }

  return result;
}

步骤3:使用示例

举个实际的例子,假设我们有一组接收User对象的函数,想转换成接收UserId的函数:

// 原参数类型
type User = { id: number; name: string; age: number };
// 新参数类型
type UserId = { userId: string };

// 输入的函数对象
const userFunctions = {
  getUserName: (user: User) => user.name,
  getUserAge: (user: User) => user.age,
  isAdult: (user: User) => user.age >= 18
};

// 转换:把UserId转成User对象(这里模拟从ID获取User的逻辑)
const transformedFunctions = transformFunctionMap(userFunctions, (params) => ({
  id: parseInt(params.userId),
  name: "Mock Name",
  age: 28
}));

// 现在可以调用新函数,传入UserId类型参数
console.log(transformedFunctions.getUserName({ userId: "123" })); // "Mock Name"
console.log(transformedFunctions.isAdult({ userId: "456" })); // true

这种方式既保留了原函数对象的键名,又确保每个新函数的返回类型和原函数完全一致,同时成功替换了参数类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:05:03