TypeScript中如何定义接收任意数量不同返回类型Supplier的函数并推导返回元组类型
TypeScript中如何定义接收任意数量不同返回类型Supplier的函数并推导返回元组类型
当然可以做到!你只需要借助TypeScript的泛型元组和映射类型,就能让编译器精准推导出返回值的元组类型,完全适配任意数量的不同Supplier参数。
先回顾你的Supplier类型定义:
type Supplier<T> = () => T;
接下来我们这样定义函数f:
function f<T extends Supplier<any>[]>(...args: T): { [K in keyof T]: ReturnType<T[K]> } { // 执行每个Supplier并返回结果,这里用as any是因为map默认返回数组而非元组,我们已经通过泛型约束好了类型,所以是安全的 return args.map(supplier => supplier()) as any; }
我来拆解一下这段代码的逻辑:
- 泛型
T extends Supplier<any>[]:用来捕获你传入的所有Supplier参数组成的元组类型(注意这里不是普通数组,TypeScript会自动把可变参数推断为元组) - 返回类型
{ [K in keyof T]: ReturnType<T[K]> }:通过映射类型遍历元组的每个索引,用内置的ReturnType工具类型提取每个Supplier的返回值类型,最终组合成和参数顺序完全对应的元组类型 - 函数体里的
args.map就是简单执行每个Supplier函数,收集结果。之所以用as any断言,是因为TypeScript的Array.map方法默认返回普通数组,而我们需要的是严格的元组类型,不过因为泛型已经约束了返回类型,这个断言不会有类型安全问题
现在试试你给出的调用场景:
const values = f(() => 3, () => "text", () => true); // 此时values的类型会被自动推导为 [number, string, boolean]
如果你想让泛型约束更严谨,也可以把Supplier<any>换成Supplier<unknown>,效果是一样的,只是语义上更强调“未知的返回类型”。
另外,如果你不想用ReturnType,也可以手动用条件类型提取返回值:
function f<T extends Supplier<any>[]>(...args: T): { [K in keyof T]: T[K] extends Supplier<infer U> ? U : never } { return args.map(supplier => supplier()) as any; }
这段代码和前面的版本功能完全一致,只是把ReturnType换成了手动的infer推导,本质是一样的。
内容来源于stack exchange
相关产品推荐
相关产品推荐

