TypeScript实现compose时如何正确推导各传入函数的参数类型
TypeScript 实现compose函数的精确类型推导方案
问题描述
实现闭包函数compose组合工具时遇到类型推导失效问题:
- 待组合的闭包函数统一遵循
(config: 任意配置) => (a: number) => number契约,例如:const func1 = (arg1: {a: number}) => (a: number) => number const func2 = (arg1: {b: string}) => (a: number) => number - compose调用形式为
const composed = compose({func1, func2}),返回的组合函数接收两个参数:- 第一个参数:传入执行链最内层的数值
- 第二个参数:可选配置对象,key与传入compose的函数名一一对应,value为对应函数所需的入参配置
- 执行逻辑等价于从右到左串行执行所有闭包返回的内层函数,例如
composed(33, {func1: {a:1}})等价于func1({a:1})(func2(undefined)(33)) - 现有实现中config参数的所有属性都被推导为
any,无法获得对应函数的入参类型提示
问题原因
原有泛型定义存在两个缺陷:
- 泛型参数
T仅约束了funcs对象的key类型,没有绑定整个funcs对象的结构,无法保留每个key对应的精确函数类型 - 映射config类型时,使用
typeof funcs[T]索引类型,其中T是所有key的联合类型,最终拿到的是所有函数类型的联合,再加上基础类型MyFunction把入参写死为any,最终推导结果全部为any
修复代码
调整泛型定义,直接绑定传入funcs对象的完整类型,再通过映射类型逐个提取每个函数的入参类型:
type ComposableFunction = (config: any) => (a: number) => number; export const compose = <T extends Record<keyof T, ComposableFunction>>(funcs: T) => { // 内部组合实现逻辑可自行补充,以下为参考实现 const funcKeys = Object.keys(funcs) as (keyof T)[]; return ( value: number, config?: Partial<{ [K in keyof T]: Parameters<T[K]>[0] }>, ) => { let execResult = value; // 按从右到左顺序执行,匹配f1(f2(value))的逻辑 for (let i = funcKeys.length - 1; i >= 0; i--) { const currentKey = funcKeys[i]; const currentInnerFn = funcs[currentKey](config?.[currentKey]); execResult = currentInnerFn(execResult); } return execResult; }; };
推导效果验证
const func1 = (arg1: {a: number}) => (a: number) => a + arg1.a; const func2 = (arg1: {b: string}) => (a: number) => a + Number(arg1.b); const composedFn = compose({func1, func2}); // 编写第二个配置参数时,TS会自动提示: // func1 对应配置类型为 {a: number} // func2 对应配置类型为 {b: string} const result = composedFn(33, {func1: {a: 1}}); // 类型校验正常,无any问题
核心要点
- 泛型参数需要直接捕获传入的整个funcs对象类型,而非仅捕获key的联合类型,才能保留每个属性的精确函数签名
- 映射配置类型时,需要针对遍历过程中的单个key
K,通过T[K]获取对应位置的函数类型,再通过Parameters提取其第一个入参类型,不能用全量key联合类型做索引
内容的提问来源于stack exchange,提问作者dnarvaez27
相关产品推荐
相关产品推荐

