TypeScript中compose函数类型定义报错及参数类型未知问题求助
解决TypeScript compose函数的类型定义问题
问题分析
原代码存在两个核心问题:
- 索引类型错误:
keyof Arr会包含数组的非数字键(如"length"),无法直接用于索引[any,...Arr]类型;同时原泛型设计将返回值元组与函数参数分离,导致类型关联断裂。 - 参数类型推断失败:独立的
Begin泛型参数无法与函数链的输入类型建立关联,导致返回函数的参数类型被推断为unknown。
解决方案
重新设计泛型约束,让函数链的输入输出类型形成强关联:
方案一:映射类型约束函数链
// 获取元组首个元素类型 type First<T extends any[]> = T extends [infer U, ...any[]] ? U : never; // 获取元组末位元素类型 type Last<T extends any[]> = T extends [...any[], infer U] ? U : never; // 获取函数的参数类型 type ArgType<F> = F extends (arg: infer A) => any ? A : never; // 获取函数的返回值类型 type ReturnType<F> = F extends (...args: any[]) => infer R ? R : never; // 约束函数元组:每个函数的参数是前一个函数的返回值 type ComposeFns<T extends any[]> = { [I in keyof T]: I extends `${number}` ? I extends "0" ? (arg: any) => any : (arg: ReturnType<T[Number(I)-1]>) => ReturnType<T[Number(I)]> : never; } & { length: T['length'] }; function compose<T extends ((arg: any) => any)[]>( ...fns: T extends ComposeFns<T> ? T : never ): (arg: ArgType<First<T>>) => ReturnType<Last<T>> { return function(val) { return fns.reduce((input, fn) => fn(input), val) as ReturnType<Last<T>>; }; }
方案二:递归类型计算返回结果
// 递归计算compose的返回函数类型 type ComposeResult<T extends any[]> = T extends [(arg: infer A) => infer R] ? (arg: A) => R : T extends [(arg: infer A) => infer R, ...infer Rest] ? ComposeResult<[(x: R) => R, ...Rest]> extends (arg: infer _) => infer FinalR ? (arg: A) => FinalR : never : never; function compose<T extends ((arg: any) => any)[]>(...fns: T): ComposeResult<T> { return function(val) { return fns.reduce((input, fn) => fn(input), val) as ComposeResult<T>; }; }
测试验证
使用你提供的测试代码:
function a(p: string): boolean { return true; } function b(p: boolean): number { return 1; } function c(p: number): Array<string> { return []; } const abc = compose(a, b, c); // 此时abc的类型被正确推断为:(arg: string) => string[]
两种方案都能解决原有的类型错误,并且正确推断返回函数的参数和返回值类型。
内容的提问来源于stack exchange,提问作者jimin hu
相关产品推荐
相关产品推荐

