推导关联函数数组的类型:参数转换后的返回类型定义
解决思路:用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
相关产品推荐
相关产品推荐

