How to use Promise.all() with Typescript

At least from TypeScript 2.7.1 onwards, the compiler seems to resolve the types without help, with a syntax like this:

Promise.all([fooPromise, barPromise]).then(([foo, bar]) => {
  // compiler correctly warns if someField not found from foo's type
  console.log(foo.someField);
});

Hat tip: @JamieBirch (from comment to @AndrewKirkegaard's answer)


If you'd like to keep type-safety, it's possible to extend the native type-definition of the Promise object (of type PromiseConstructor) with additional overload signatures for when Promise.all is called with a finite number of not-necessarily inter-assignable values:

interface PromiseConstructor
{
    all<T1, T2>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>;
    all<T1, T2, T3>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>]): Promise<[T1, T2, T3]>;
    ...
}

Add as many overloads as you need. This approach provides full type-safety for all elements in the value argument of the onfulfilled callback:

Promise.all([1, "string", true]).then(value =>
{
    let a: number = value[0]; // OK
    let b: number = value[1]; // Type 'string' is not assignable to type 'number'.
    ...
});

Its generally best to have arrays with consistent types. You can do the following manually though (passing in generic arguments):

Promise.all<Aurelia, void>(
  [aurelia.start(), entityManagerProvider.initialize()
])
.then(results => {
    let aurelia = results[0];
    aurelia.setRoot();
});

Since Promise::all is a generic function, you can declare the return types of each promise like this:

Promise.all<Aurelia, void>([
  aurelia.start(),
  entityManagerProvider.initialize()
])
.then(([aurelia]) => aurelia.setRoot());

Tags:

Typescript