To effectively handle this situation, we can utilize TypeScript's Generic Rest Parameters.
By implementing this approach, we can define a generic tuple type that captures the specific type of each argument when the function is invoked.
Let's delve into the process:
Initially, we will capture the type of each argument passed to the function.
const firstSettledValue = <P extends Promise<any>[]>(...promises: P) => {}
const v = firstSettledValue(
Promise.resolve('Hello World'),
Promise.resolve(15),
Promise.resolve(false)
)
Subsequently, we can derive a union type of all the arguments, i.e., the elements of P
, using P[number]
.
type U = P[number] // string | number | boolean
It is important to note that in the aforementioned example, P[0]
corresponds to the type string
, P[1]
corresponds to the type number
, and so forth.
However, direct usage of P[Number]
is not feasible in the given context because our elements are promises and we need to extract their value types.
To facilitate this, we can introduce a helper type as follows:
type ValueType<T> = T extends Promise<infer U>
? U
: T;
Upon receiving a Promise<T>
, the aforementioned helper will yield T
.
Finally, we integrate these strategies together:
const firstSettledValue = <P extends Promise<any>[]>(...promises: P): Promise<ValueType<P[number]>> => {
const randomIndex = Math.floor(Math.random() * 100) % promises.length;
return promises[randomIndex];
};
const v = firstSettledValue(
Promise.resolve('Hello World'),
Promise.resolve(15),
Promise.resolve(false)
);
type ValueType<T> = T extends Promise<infer U>
? U
: T;
Playground Link
At this juncture, v
possesses the type
Promise<string | number | boolean>
, reflecting the promises specified during the call.