Promise.all types under the hood in TypeScript
Today we discuss Promise.all
This is helpful in case we need to wait for all the values (e.g. we pass [Promise<number>, 42, Promise<string>]
and expect to have Promise<[number, 42, string]>
at the end).
Let's solve it 🚀
Iteration over tuple elements
Previously, one of the challenges in easy category was Unwrapping the Promises where we imitated await
in types:
This will help to iterate over tuple elements and replace Promise
with the resolved type.
We already know how to iterate over tuple elements with Making object out of tuple but here we have the difference:
- If we want to have elements of tuple inside the object type, we use Mapped Types:
- If we need to work with tuple elements and leave the structure as is, we use Type inference in conditional types with Rest elements in Tuples:
As we need to transform the elements inside the tuple but still need to have the tuple at the end, we will use the second approach. Let's go over all elements and unwrap it with Awaited
:
The only thing we need to do is to apply it to PromiseAll
:
Let's see what happened in Playground. We still have failed tests. But why?
Fixing the issues with values
If we hover over constants we will see that the result is Promise<[]>
, but we expected it to have elements' types inside a tuple.
This happens because as const
converts an array to a tuple. For tuples T extends [infer H, ...infer Tail] ? true : false
returns false
because we forgot readonly
keyword.
But instead of changing PromiseReducer
let's have a look at promiseAllTest3
:
Type T
is inferred as (number | Promise<number>)[]
instead of [number, number, Promise<number>]
. There is an approach to have values as tuple instead of array in types:
- We added
[...T]
instead ofT
- We say that
[...T]
isreadonly
to work with tuples only - We added Generic Constrain to use spread in tuples
All together:
That's it 🔥
Solution is available on Playground
Have a wonderful evening 🌇
typescript