如何为函数组合生成的函数记录正确添加TypeScript类型?
问题描述
尝试通过reduce方法生成一个函数记录,将列表中的每个函数与setTimeout进行组合,但添加类型时出现错误:
A spread argument must either have a tuple type or be passed to a rest parameter
测试代码如下:
const funcA = (n: number) => `${n}` const funcB = (s: string) => s.length // Cannot do this with a reduce const functions = [funcA, funcB] const exported = functions.reduce((acc, func) => ({ ...acc, // Args type is args: [s: string] | [n: number] [func.name]: (...args: Parameters<typeof func>) => setTimeout(() => func(...args), 100) }), {}) // Expected output const recordOfFunctions = { funcA: (...args: Parameters<typeof funcA>) => setTimeout(() => funcA(...args), 100), funcB: (...args: Parameters<typeof funcB>) => setTimeout(() => funcB(...args), 100), }
解决方法
问题根源在于TypeScript默认会将数组中不同函数的类型合并为联合类型,导致Parameters<typeof func>变成联合元组,展开时不符合类型校验规则。以下是具体修复步骤:
1. 用const断言固定数组元素的精确类型
给functions数组添加as const断言,让TypeScript保留每个函数的具体类型,而非合并为模糊的联合类型:
const functions = [funcA, funcB] as const;
2. 定义类型工具转换函数数组为目标记录类型
创建一个类型工具,将函数数组映射为键为函数名、值为包装后函数的记录类型:
type FunctionsToRecord<T extends readonly ((...args: any[]) => any)[]> = { [K in T[number]['name']]: (...args: Parameters<Extract<T[number], { name: K }>>) => ReturnType<typeof setTimeout> };
该类型会遍历数组中每个函数的名称,提取对应函数的参数类型,生成符合预期的包装函数类型。
3. 给reduce指定正确的类型约束
在reduce中,通过类型断言明确初始值和累加器的类型为目标记录类型:
const exported = functions.reduce((acc, func) => ({ ...acc, [func.name]: (...args: Parameters<typeof func>) => setTimeout(() => func(...args), 100) }), {} as FunctionsToRecord<typeof functions>);
完整可运行代码
const funcA = (n: number) => `${n}`; const funcB = (s: string) => s.length; // 固定数组元素的精确类型 const functions = [funcA, funcB] as const; // 定义类型转换工具 type FunctionsToRecord<T extends readonly ((...args: any[]) => any)[]> = { [K in T[number]['name']]: (...args: Parameters<Extract<T[number], { name: K }>>) => ReturnType<typeof setTimeout> }; // 生成带正确类型的函数记录 const exported = functions.reduce((acc, func) => ({ ...acc, [func.name]: (...args: Parameters<typeof func>) => setTimeout(() => func(...args), 100) }), {} as FunctionsToRecord<typeof functions>); // 类型校验测试 exported.funcA(123); // 参数类型为number,符合要求 exported.funcB("hello"); // 参数类型为string,符合要求
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

