You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为函数组合生成的函数记录正确添加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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 21:05:48