← All tasksTypeScript · Senior

A typed Promise.all for tuples

Write all(values), an analogue of Promise.all without using Promise.all itself. It waits for all values (promises or plain ones), returns the results in the same order, and rejects with the first error.

The main thing here is the type: for all([1, Promise.resolve("a")]) the result must be Promise<[number, string]>, a tuple, not (string | number)[]. Nested promises are unwrapped down to the value.

Tests (7)

Type tests are checked by the TypeScript compiler in strict mode. Expect<Equal<A, B>> passes when the types match exactly, and // @ts-expect-error passes when the next line does not compile. The first run downloads the compiler, so it takes a few seconds.

  1. types
    const p = all([1, Promise.resolve('a'), Promise.resolve(true)]);
    type _ = Expect<Equal<typeof p, Promise<[number, string, boolean]>>>;
  2. types
    const p = all([1, 'x'] as const);
    type _ = Expect<Equal<typeof p, Promise<[1, 'x']>>>;
  3. types
    const p = all([] as unknown as [Promise<Promise<number>>, string]);
    type _ = Expect<Equal<typeof p, Promise<[number, string]>>>;
  4. expect(await all([1, Promise.resolve(2), wait(20).then(() => 3)])).toEqual([1, 2, 3]);
  5. const slow = wait(30).then(() => 'slow');
    const fast = Promise.resolve('fast');
    expect(await all([slow, fast])).toEqual(['slow', 'fast']);
  6. await expect(all([Promise.resolve(1), Promise.reject(new Error('boom'))])).rejects.toThrow('boom');
  7. expect(await all([])).toEqual([]);