6.1 Naive version (lower difficulty)
type NaiveFlat<T extends any[]> = {
[K in keyof T]: T[K] extends any[] ? T[K][number] : T[K]
}[number];
The solution of naive version is mapped type which traverse through type T
given as argument. Important parts:
-
T[K] extends any[]
- question if value type of propertyK
is an array -
T[K] extends any[] ? T[K][number] : T[K]
- ifT[K]
is an array we get its value type by indexed type[number]
.number
is correct key ofT[K]
asT[K]
was checked before for being an array, and array has number keys -
[number]
at the end has a purpose of getting all value types of produced type
6.2 Deep version (higher difficulty)
type DeepFlat<T extends any[]> = {
[K in keyof T]: T[K] extends any[] ? DeepFlat<T[K]> : T[K]
}[number]
The solution of deep version is different only in one point, instead of T[K][number]
we go further and call DeepFlat<T[K]>
so its recursive type, it calls itself. Thanks to the recursive nature we traverse the object until value type is not an array what is visible in "else" part : T[K]
The full code with test suite can be found in The Playground
This series will continue. If you want to know about new exciting questions from advanced TypeScript please follow me on dev.to and twitter.
Top comments (6)
Really liked this one, thanks!
Accidentally built DeepFlat, while trying to build a naive one lol
Here is another solution that utilizes array desctructing:
So I tried in TypeScript Playground and the following seems also a valid solution for the naive problem:
type NaiveFlat<T extends any[]> = T[number] extends any[] ? T[number][number] : T[number]
But this approach doesn't seem to work for DeepFlat
type DeepFlat<T extends any[]> = T[number] extends any[] ? DeepFlat<T[number]> : T[number]
It screems about that it circularly references itself. But doesn't it do that in your approach too? Why is it not an error in your case?
Hi, thanks for the comment.
In order to avoid this message we can make a trick, and the trick is to exactly use mapped type. Pay attention that I can take your code and put into mapped type and it doesn't complain anymore:
The bit that I'm confused about is this:
[number]
.You say:
How is this exactly working?
Edit: Had a lot more of a playaround in this post I'd care to hear your thoughts there.
my naive version was really naive
in my defence, task said tuple of tuples)