TypeScript: Promise.all doesn't handle union types
Update
This is one of the cases, where type inference with current promise type declarations fails. Simplest solution is to just add the generic type argument manually:
const promisable: Promisable = ...
const res = await Promise.all<string | number>([promisable()]);
// res: (string|number)[]
You might infer string | number
automatically:
type PromiseReturn<T> = T extends () => Promise<infer I> ? I : never
const res = await Promise.all<PromiseReturn<Promisable>>([promisable()]);
With TypeScript 4.1: More complex, potentially nested Promise types can be resolved and flattened with a custom recursive Awaited
type like this:
type Awaited<T> = T extends PromiseLike<infer U> ? Awaited<U> : T;
Playground
Old answer
Update: The awaited
type operator is delayed to later versions - not clear whether it will be released at all.
This is a known issue. Good news: TS 3.9 (beta soon) will come out with improved promise types:
I would like to reintroduce the
awaited
type operator from #17077 to meet our needs for a mechanism to recursively unwrap a Promise-like type for methods likePromise.all
,Promise.race
,Promise.allSettled
,Promise.prototype.then
, andPromise.prototype.catch
.
Type declarations of Promise.all
and others use the new awaited
type operator. If you test with the nightly build, Promise.all
now correctly resolves to Promise<(string | number)[]>
:
type Promisable = (() => Promise<string>) | (() => Promise<number>);
declare const promisable: Promisable
const res = await Promise.all([promisable()]); // res: (string | number)[]
In contrast, TS 3.8 can't handle it. For versions < 3.9, you can manually assign the generic type argument:
declare const promisable: Promisable
const res = await Promise.all<string | number>([promisable()]); // res: (string | number)[]