#20Medium

Promise.all

Implement a type-safe version of Promise.all that preserves tuple types and recursively unwraps nested promises. Master advanced TypeScript techniques including recursive types, mapped types, and conditional types in this medium-level challenge on TypeScriptPro.

In this medium-level challenge, you'll implement a type-safe version of Promise.all that preserves tuple types and recursively unwraps nested promises. This challenge goes beyond basic promise handling by requiring you to preserve the exact tuple structure of the input array while recursively unwrapping all nested promises.

Challenge Instructions: Promise.all

Medium

Type the function PromiseAll that accepts an array of PromiseLike objects, the returning value should be Promise<T> where T is the resolved result array.

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise<string>((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
 
// expected to be `Promise<[number, 42, string]>`
const p = PromiseAll([promise1, promise2, promise3] as const)

Change the following code to make the test cases pass (no type check errors).

Loading...

Video Walkthrough

Detailed Explanation

The key insight is that we need to preserve the exact tuple type of the input array while recursively unwrapping all promises. Here's the solution:

type RecursivelyUnwrapPromise<T> =
  T extends PromiseLike<infer Val> ? RecursivelyUnwrapPromise<Val> : T
 
declare function PromiseAll<T extends unknown[]>(
  values: readonly [...T],
): Promise<{ [K in keyof T]: RecursivelyUnwrapPromise<T[K]> }>

Let's break this down:

  1. Input Constraint: T extends unknown[] ensures the input is an array type
  2. Tuple Preservation: readonly [...T] preserves the exact tuple structure (e.g., [number, number, number] instead of number[])
  3. Recursive Unwrapping: RecursivelyUnwrapPromise<T[K]> recursively unwraps each promise in the tuple, by calling itself with the value of the promise if that value is PromiseLike.
  4. Mapped Types: { [K in keyof T]: ... } maps over each element in the tuple
  5. Promise Wrapping: The result is wrapped in Promise<...> to match the expected return type

The recursive utility type RecursivelyUnwrapPromise<T> handles cases where promises might be nested within promises, ensuring all levels are properly unwrapped while maintaining type safety.

This challenge helps you understand advanced TypeScript concepts like recursive types, mapped types, and how to preserve precise type information through complex transformations.

This challenge is originally from here.

Share this challenge

Join early, learn faster.

Be the first to access the course, unlock exclusive launch bonuses, and get special early-bird pricing before anyone else.

No spam, unsubscribe at any time. We respect your privacy.

Limited Availability

Only 27 Spots left

Early Access

Get 1 month early access

>75% Off

Pre-Launch discount