TypeScript如何将n元组getter函数类型转为返回值n元组类型?
完美解决:用TypeScript映射类型实现元组返回值推导
嘿,这个需求太常见了!你完全不用写一堆重复的重载,TypeScript的映射类型结合条件类型推断就能优雅解决这个问题,而且支持任意长度的函数数组。
最终实现代码
// 定义ValueTupleOf类型:提取函数元组中每个函数的返回值组成新元组 type ValueTupleOf<T extends readonly (() => any)[]> = { [K in keyof T]: T[K] extends () => infer R ? R : never; }; // 你的getValues函数,现在能自动推导精确的元组类型 function getValues<A extends (() => any)[]>(getters: A): ValueTupleOf<A> { // 这里需要类型断言,因为Array.map默认返回数组而非元组 return getters.map(getter => getter()) as ValueTupleOf<A>; }
为什么这能工作?
让我拆解一下关键部分:
- 元组约束:
T extends readonly (() => any)[]确保输入是一个由函数组成的元组(加上readonly是为了兼容只读元组场景,去掉也不影响核心功能)。 - 映射元组:
[K in keyof T]是对元组的每个索引位置进行遍历——TypeScript会把元组的数字索引当作key,所以映射后依然会保留元组的结构(而不是变成普通数组)。 - 提取返回值:
T[K] extends () => infer R ? R : never用条件类型推断,把每个位置的函数类型拆解,提取出它的返回值类型R。
测试验证
来试试实际用例,类型推导完全精确:
const result = getValues([ () => "Hello TypeScript", () => 2024, () => { name: "Natasha" } ]); // result的类型会被自动推断为: // [string, number, { name: string }]
为什么不用重载?
你原来的重载方案虽然能工作,但有明显缺点:
- 扩展性极差,函数数组长度超过3、4个就得继续写新的重载,非常繁琐。
- TypeScript对重载的类型推断有时候会出现边界情况(比如传入动态生成的数组时,重载可能匹配失败)。
- 映射类型是TypeScript类型系统原生支持的方案,代码更简洁、更易维护。
内容的提问来源于stack exchange,提问作者Natasha
相关产品推荐
相关产品推荐

