'How to use Promise.all() with Typescript

Here is what I want to do:

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

aurelia.start() returns an Aurelia type, while initialize() returns void.

The compiler gives an error message that the type cannot be inferred from the usage.

What I am trying to achieve is to get them to run at the same time, as they are both very long processes, then run Aurelia.setRoot();



Solution 1:[1]

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();
});

Solution 2:[2]

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());

Solution 3:[3]

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)

Solution 4:[4]

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'.
    ...
});

Solution 5:[5]

PART 1

There are functions you need to understand A) Promise.all and B) Promise.then:

A) the type definition of Promise.all is a function:

    all<T>(values: readonly (T | PromiseLike<T>)[]): Promise<T[]>;

B) the type definition of Promise.then is a function that is a bit more complex:

    then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;

PART 1.a

Promise.then's type definition is a lot but it can be broken down into small parts:

then<TResult1 = T, TResult2 = never> a function then with 2 generics TResult1, TResult2. The < > means we can set and use values inside them later - they are called generics.

The then function itself: (onfulfilled?: ..., onrejected?: ...): Promise<TResult1 | TResult2>.

PromiseLike is a helper type and the same as Promise (for an intro lesson).

onfulfiled and onrejected are functions in the form of: (value: T) => (TResult1 OR PromiseLike<TResult1>) OR undefined OR null. Notice the generic T is used here.

PART 2 -

Promise itself has a generic interface: interface Promise<T>. The <T> is a/the generic.

So when you call

Promise.all<SomeCoolType>([a(), b(), c()]).then( value => doSomething(value) )

your generic is SomeCoolType and in this example some cool type is

interface SomeCoolType = [A() => string, B() => boolean, C() => number]

Now remember that A B C have to be Promises. And this makes it so your value in .then( value => ... is going to the result of SomeCoolType which for us is calling all those functions, the result is [string, boolean, number].

CONCLUSION -

Concretely, the array of function/promises you pass into you Promise.all<T> are generics that are used in .then(result => ...). The return/resolve value of those promises will become the value/type of result.

Example: Promise.all<[Promise<() => string>]>([returnStringAsync()]).then(result => console.log(typeof result === "string")); # => true

Solution 6:[6]

For anyone looking for a way to use Promise.all in React TypeScript:

Promise.all<Foo, Bar>(fooPromise, barPromise)

where fooPromise and barPromise are the promises you want to execute in parallel, fooPromise returns a foo type response, and barPromise returns a bar type response.

If you check the response at .then, you'll see the response is a tuple: [Foo, Bar].

Solution 7:[7]

When using promises that return values, my favorite using of Promise.all() is using array destructuring as below. Using await is more readable and destructuring is filling up the right variables.

export interface IDeveVersionHubDataService {
    getBuildFilterDeveVersions(): Promise<IBuildFilterDeveVersionDto[]>;
    getBuildFilterUsers(): Promise<IBuildFilterUserDto[]>;
}
const loadDeveVersions = deveVersionHubDataService.getBuildFilterDeveVersions();
const loadUsers = deveVersionHubDataService.getBuildFilterUsers();

const [deveVersions, users] = await Promise.all([loadDeveVersions, loadUsers]);     

Solution 8:[8]

A full example:

type returnString = string;
type returnNumberType = number;
type jobsType = [Promise<returnString>, Promise<returnNumberType>];

const returnString = async (): Promise<returnString> => {
  return 'This is a string';
};

const returnNumber = async (): Promise<returnNumberType> => {
  return 123;
};

const jobs = [];

jobs.push(returnString());

if (Math.random() > 0.5) {
  jobs.push(returnNumber());
}

(async () => {
  const results = await Promise.all(jobs as jobsType);
  // results now has the correct.
  // tslint:disable-next-line: no-console
  console.log(results);
})();

Solution 9:[9]

I somehow landed here when I was looking for return type of Promise.all() since straightforward [Promise<any>, Promise<any>] is obviously not working.

Eventually it turned out to be simplier than it seems:

const severalMongoDbOperations: Promise<[DeleteWriteOpResultObject, UpdateWriteOpResult]> =
  () => Promise.all([
    mongo.deleteOne({ ... }),
    mongo.updateOne({ ... })
  ]);

Later it can be used with .then() or:

try {
  const ops: [DeleteWriteOpResultObject, UpdateWriteOpResult] = await severalMongoDbOperations();
} catch (e) {
  // Process rejection
}

Solution 10:[10]

I have the same issue with you, but with this code, all work perfectly.

type TList = Promise<Aurelia> | Promise<void>;

const foo: TList[] = [aurelia.start(), entityManagerProvider.initialize()];

Promise.all<TList>(foo).then((results) => {
    let aurelia = results[0];
    aurelia.setRoot();
});

Solution 11:[11]

Promise.all returns "a single Promise that resolves to an array of the results of the input promises" (from MDN).

You can get the results of all the promises if you await the promise all.

        const [tomorrow, today, yesterday] = await Promise.all([
            fun('tomorrow'),
            fun('today'),
            fun('yesterday')
        ]);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3
Solution 4
Solution 5 Taysky
Solution 6 noobmaster007
Solution 7
Solution 8 Henry Zhuang
Solution 9 Paul T. Rawkeen
Solution 10 AndriyFM
Solution 11