如何 return 接口中方法的 ReturnType 的元组,它是一种可变参数

How to return a tuple of ReturnType of a method in the interface which is a type of variable arguments

我想完成编写如下所示的方法。接口 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]

我怎样才能做到没有任何错误?

您可以将函数表示为作用于泛型的类型 mapped tuple。如果输出是 T 类型的元组,那么输入是 {[I in keyof T]: A<T[I]>} 类型的元组,意思是:对于 T 元组中的每个索引 I,输入应该是输入 A<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(...) 是否实际生成了预期类型的​​值;即使一般表示这种转换也需要类似 higher kinded types 之类的东西,目前 TypeScript 不支持它们(参见 microsoft/TypeScript#1213 for a relevant feature request). The easiest thing to do is what I've done above: just assert 输出类型为 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> utility type表示这个转换,但是写起来比较麻烦:

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 link to code