让我们假设您有一个函数,该函数具有一个getter函数数组作为输入,并返回一个具有相同返回值的数组(长度相同)。
在下面的示例中,类型定义type ValueTupleOf<...> = ...
的外观如何?
function getValues<A extends (() => any)[]>(getters: A): ValueTupleOf<A> {
return getters.map(getter => getter())
}
编辑:当然,我可以执行以下操作,但我希望有更好的解决方案:
function getValues<A1>(getters: [() => A1]): [A1]
function getValues<A1, A2>(getters: [() => A1, () => A2]): [A1, A2]
function getValues<A1, A2, A3>(getters: [() => A1, () => A2, () => A3]): [A1, A2, A3]
// ... etc
function getValues(getters: any): any {
return getters.map(getter => getter())
}
答案 0 :(得分:2)
您在这里...(不言自明)此外,demo
type ReturnTypes<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => infer R ? R : never
}
type Getter<T = {}> = () => T;
function getValues<Getters extends Array<Getter>>(getters: Getters) {
return <ReturnTypes<Getters>>getters.map(getter => getter())
}
let values = getValues(<[() => "a1", () => "a2"]>[() => "a1", () => "a2"])
/* type of values is ["a1", "a2"] (hover to check)
In latest TS version you can use <const> to make tuples,
instead of writing things twice like I did here
*/
type foo = ReturnTypes<[() => "a1", () => "a2"]>;
// foo is ["a1", "a2"]
getValues(<[(x: string) => "a1"]>[(x: string) => "a1"])
// Also type-safe ^ gives error
答案 1 :(得分:1)
简短答案
坚持超载。一开始他们可能看起来像很多工作,但替代方案甚至更糟。
好答案
TypeScript没有可变参数类型,因此,为了保留元组的顺序,您必须使用技巧。但是,此技巧很丑陋且有局限性。
import { Reverse } from 'typepark';
type Thunk<T> = () => T;
type ReturnTypesOf<T extends Thunk<any>[], Length extends number = T['length'], Queue extends any[] = [], Index extends number = Queue['length']> = {
done: Queue;
next: ReturnTypesOf<T, Length, Prepend<ReturnType<T[Index]>, Queue>>;
}[Yield<Queue, Length>];
type Yield<Queue extends any[], Length extends number> =
Queue['length'] extends Length
? 'done'
: 'next';
type Prepend<T, U extends any[]> =
((head: T, ...tail: U) => void) extends ((...all: infer V) => void)
? V
: [];
type T1 = ReturnTypesOf<[() => 1, () => 'foo']>; // ["foo", 1]
type T2 = Reverse<T1>; // [1, "foo"]
如您所见,它可以解决问题,但是:
@jcalz的答案
注释中提到的jcalz可以使用映射的元组类型。如果您不介意一个接一个地传递参数(而不是传递数组),则可以这样做:
type AnyFunction = () => any;
/**
* Mapped type, but for tuples.
*/
type ReturnTypesOf<T extends AnyFunction[]> = {
[K in keyof T]: T[K] extends AnyFunction
? ReturnType<T[K]>
: never
};
function getValues<T extends AnyFunction[]>(...functions: T) {
return functions.map(callback => callback()) as ReturnTypesOf<T>;
}
const values = getValues(
() => "foo",
() => 42
)