how to avoid union type for each resulting element (needed [valueOfTypeOne, ValueOfTypeTwo] instead of (valueOfTypeOne | ValueOfTypeTwo)[]) in such scenario ?
const [valueOfTypeOne, ValueOfTypeTwo] = await Promise.all(
[
fetchTypeOne(),
fetchTypeTwo(),
].map((promise) => promise.catch(() => null)),
);
CodePudding user response:
Using .map()
on a tuple will essentially convert the tuple to an array type and you will lose the type information. See here https://github.com/microsoft/TypeScript/issues/6574
One way to fix this is two append the catch
to each Promise.
const [valueOfTypeOne, ValueOfTypeTwo] = await Promise.all(
[
fetchTypeOne().catch(() => null),
fetchTypeTwo().catch(() => null),
],
);
CodePudding user response:
A nice utility function that will do the mapping for us and hide away the type of map
can do the trick:
function catchToNull<P extends Promise<any>[]>(...promises: P): { [K in keyof P]: Promise<Awaited<P[K]> | null> } {
return promises.map((p) => p.catch(() => null)) as never;
}
It iterates through each promise and unwraps it, wrapping it back with null
.
You would use it like this:
const [valueOfTypeOne, valueOfTypeTwo] = await Promise.all(
catchToNull(
fetchTypeOne(),
fetchTypeTwo(),
)
);
And in the case of an array of promises, use spread:
catchToNull(...arrayOfPromises);
You might find that you need to type the array of promises as a tuple if necessary:
catchToNull<[Promise<number>]>(...onlyOnePromiseInThisArray);
You can find and try this solution here.