首页 > 解决方案 > 如何在接口中返回一个方法的 ReturnType 元组,它是一种可变参数

问题描述

我想写完一个如下所示的方法。该接口A是生成器的配置类型,我将对不同类型的生成器进行不同的配置,并在函数f中一次使用它们,以便在一个元组中获取所有生成的值。

interface A<Output> {
   f: () => Output;
};

const a: A<string> = {
   f: () => 'Hello',
};

const b: A<number> = {
   f: () => 42,
};

function f(...x: ???): ??? {
   return x.map(x => x.f());
}

const y: [string, number] = f(a, b);
console.log(y) // ['Hello', 42]

我怎样才能做到这一点而不会出现任何错误?

标签: typescripttypescript-typingstypescript-generics

解决方案


您可以将函数表示为作用于泛型映射元组的类型。如果输出是 type 的元组T,那么输入是 type ,意思是:对于元组中的{[I in keyof T]: A<T[I]>}每个索引,输入应该是 type ,输出应该是 type :ITA<T[I]>T[I]

function f<T extends any[]>(...x: { [I in keyof T]: A<T[I]> }) {
    return x.map(x => x.f()) as T;
}

请注意,编译器不会也可能永远无法验证x.map(...)实际产生了预期类型的​​值;即使通常表示这样的转换也需要TypeScript 目前不支持的更高种类的类型(有关相关功能请求,请参见microsoft/TypeScript#1213 )。最简单的事情就是我在上面所做的:只需断言输出将是 type T,通过编写x.map(...) as T.


让我们确保它有效:

const y = f(a, b); // [string, number]
console.log(y[0].toUpperCase()) // "HELLO"
console.log(y[1].toFixed(2)) // "42.00"

是的,看起来不错。


哦,您可以使用ReturnType<T>实用程序类型将此转换表示为某种东西,但编写起来更麻烦:

function f<T extends A<any>[]>(...x: T) {
    return x.map(x => x.f()) as { 
      [I in keyof T]: ReturnType<Extract<T[I], A<any>>["f"]> 
    };
}

不过,它在调用者方面的行为类似。


Playground 代码链接


推荐阅读