typescript - Convertir un array de promesas en una sola promesa que podría ser uno de los tipos incluidos: [P<string>, P<number>] -> Promise<string | number>
Estoy intentando crear una función que devuelva el primer valor resuelto de un arreglo de Promesas
const firstSettledValue = (...promises: Array<Promise<any>>): Promise<any> {
// ...
}
const v = firstSettledValue(
new Promise<string>(),
new Promise<number>(),
new Promise<boolean>()
)
v // Promise<string | number | boolean>
Respuesta #1
Puedes simplemente usar Promise.race():
const v = Promise.race([
new Promise<string>(() => {}),
new Promise<number>(() => {}),
new Promise<boolean>(() => {})
]);
v // Promise<string | number | boolean>
El tipo de retorno se infiere correctamente.
Respuesta #2
Podemos usar los parámetros rest genéricos de TypeScript para manejar esto con precisión.
Esto nos permite declarar un tipo de tupla genérico que captura el tipo individual de cada argumento cuando se llama a la función.
Vamos a desglosarlo.
Primero capturaremos el tipo de cada argumento pasado a la función
const firstSettledValue = <P extends Promise<any>[]>(...promises: P) => {}
const v = firstSettledValue(
Promise.resolve('Hello World'),
Promise.resolve(15),
Promise.resolve(false)
)
Ahora, podemos obtener un tipo unión de cada uno de todos los argumentos, es decir, los elementos de P, mediante P[number].
type U = P[number] // string | number | boolean
Tenga en cuenta que en lo anterior P[0] es del tipo string, P[1] es del tipo number, y así sucesivamente.
Sin embargo, no podemos usar P[Number] directamente en el código anterior porque nuestros elementos son promesas y necesitamos extraer sus tipos de valor.
Para hacer eso, podemos introducir un pequeño tipo auxiliar
type ValueType<T> = T extends Promise<infer U>
? U
: T;
Dado un Promise<T>, el auxiliar anterior produce T.
Finalmente componemos estas técnicas juntas
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;
Enlace del parque
Y hemos terminado. v tiene tipo Promise<string | number | boolean>, basado en las promesas especificadas en la llamada.
