如何在TypeScript中向HOC函数传递函数数组且不丢失原始类型?
解决函数/函数数组处理时的类型保留问题
你的核心需求是实现一个工具函数,既能处理单个函数并返回原类型函数,也能处理函数数组并返回保持原顺序且每个元素保留自身类型的数组。之前的实现问题在于泛型推断时丢失了数组元素的具体类型,变成了联合类型。
问题分析
你原来的写法中,泛型T被约束为单个函数类型,当传入函数数组时,T会被推断为数组内所有函数的联合类型,导致返回的数组是T[](即联合类型数组),而非保留原结构的元组。这就造成解构后的变量类型变成了联合类型,而非各自的原始函数类型。
正确实现方案
方法1:函数重载(推荐,可读性更高)
通过定义两个重载签名,分别处理单个函数和函数数组的场景,让TypeScript精准推断返回类型:
// 重载1:处理单个函数 function doMagicToCallBackOrCallBacks<T extends (...args: any) => any>(arg: T): T; // 重载2:处理函数数组(支持元组类型推断) function doMagicToCallBackOrCallBacks<T extends readonly ((...args: any) => any)[]>(arg: T): T; // 核心实现 function doMagicToCallBackOrCallBacks(arg: any) { if (Array.isArray(arg)) { // 对数组中每个函数执行你的逻辑 return arg.map(fn => { // 这里替换成你的"magic"逻辑 return fn; }); } else { // 对单个函数执行你的逻辑 return arg; } }
方法2:条件类型泛型
如果不想用重载,可以通过条件类型让泛型自动匹配输入类型并返回对应结果:
function doMagicToCallBackOrCallBacks< T extends ((...args: any) => any) | readonly ((...args: any) => any)[] >(arg: T): T extends readonly ((...args: any) => any)[] ? T : T extends (...args: any) => any ? T : never { if (Array.isArray(arg)) { return arg.map(fn => { // 执行magic逻辑 return fn; }) as T; } else { return arg as T; } }
测试验证
用你的示例代码测试,两种方案都能正确保留类型:
function basicFunction(number: number) { return number.toString(); } function anotherFunction() {} // 单个函数场景:类型为(number: number) => string const basicFunctionButWithMagic = doMagicToCallBackOrCallBacks(basicFunction); // 数组场景:解构后类型分别为(number: number) => string 和 () => void const [firstFunction, secondFunction] = doMagicToCallBackOrCallBacks([basicFunction, anotherFunction]);
关键原理
- 重载签名让TypeScript根据输入类型(单个函数/函数数组)选择对应的返回类型;
- 当输入是数组时,约束
T为readonly ((...args: any) => any)[]会让TypeScript将数组推断为元组类型,而非普通的联合类型数组,从而保留每个元素的原始类型。
内容的提问来源于stack exchange,提问作者Dems314
相关产品推荐
相关产品推荐

