DEV Community

Pragmatic Maciej
Pragmatic Maciej

Posted on • Updated on

Advanced TypeScript Exercises - Question 6

Hi folks! ✋ Today we will play a bit with mapped types. The exercise is about getting all value types from the tuple type. Question will be slightly different (as I am still playing with the series format) and will be split into two tasks with different difficulty level.

6.1 Naive version (lower difficulty)

type NaiveFlat<T extends any[]> = unknown // 🔥 here your code
// test case
type Naive = [['a'], ['b', 'c'], ['d']];
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]>
// should evaluate to "a" | "b" | "c" | "d"
Enter fullscreen mode Exit fullscreen mode

Our goal is to make type level function NaiveFlat which will take nested tuple and get all value types from it. Naive implementation should work with 1 level of nesting so tuple of tuples.

6.2 Deep version (higher difficulty)

type DeepFlat<T extends any[]> = unknown // 🔥 here your code
// test case
type Deep = [['a'], ['b', 'c'], [['d']], [[[['e']]]]];
type DeepTestResult = DeepFlat<Deep>  
// should evaluate to "a" | "b" | "c" | "d" | "e"
Enter fullscreen mode Exit fullscreen mode

We go level up. Deep version should flat any level of nested tuples.
The questions and ready to start code is available in The Playground

Post your answers in comments. Have fun! Answer will be published soon!

BTW please share your opinion if such questions with few options works for you? I want to know what you think about such format, thanks!

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)

Collapse
 
kashyaprahul94 profile image
Rahul Kashyap • Edited

This time, after a lot of thought & attempts :P

Naive version -

// Basic level 1 values of a type
type Level1<T extends any[]> = T[number];

// Level 2 making use of level 1 twice
type Level2<T extends any[]> = Level1<Level1<T>>;


type NaiveFlat<T extends any[]> = Level2<T>;

type Naive = [['a'], ['b', 'c'], ['d']];
type NaiveTestResult = Assert<NaiveFlat<Naive>, "a" | "b" | "c" | "d">; // should be true

Deep version-

// Recursive mapped type for nested level
type NestedLevel<T extends any[]> = {
  [K in keyof T]: T[K] extends any[] ? NestedLevel<T[K]> : T[K];
}[number];


type DeepFlat<T extends any[]> = NestedLevel<T>;

type Deep = [['a'], ['b', 'c'], [['d']], [[[['e']]]]];
type DeepTestResult = Assert<DeepFlat<Deep>, "a" | "b" | "c" | "d" | "e"> // should be true

Playground link

Collapse
 
macsikora profile image
Pragmatic Maciej • Edited

Nice but the solution can be simpler 😉

Collapse
 
kashyaprahul94 profile image
Rahul Kashyap

Yeah, realised it later. Updated the answer :)

Collapse
 
avfirsov profile image
Andrew Firsov • Edited

Deep Version -- Hard way:

type OmitFirstValue<T extends unknown[]> = ((...args: T) => void) extends (x: any, ...rest: infer R) => void
  ? R
  : never;

type Prepend<T extends unknown[], V> = ((x: V, ...args: T) => void) extends (...result: infer R) => void ? R : never;

// Question 6.2
type DeepFlat<T extends any[]> = {
  true: T[0] extends any[] ? DeepFlat<T[0]> : T[0];
  false: Prepend<[DeepFlat<OmitFirstValue<T>>], T[0] extends any[] ? DeepFlat<T[0]> : T[0]>[number];
}[T['length'] extends 1 ? 'true' : 'false']
Enter fullscreen mode Exit fullscreen mode

Deep version -- easy way:

type DeepFlat<T extends any[]> = {
  [K in keyof T]: T[K] extends any[] ? DeepFlat<T[K]> : T[K];
}[number]
Enter fullscreen mode Exit fullscreen mode
Collapse
 
nmonastyrskyi profile image
Nikita Monastyrskiy

Cool exercise! Like this format!

Collapse
 
macsikora profile image
Pragmatic Maciej

Tnx Nikita for your feedback. Maybe will get back to the series some day. Had lack of motivation lately. Tnx again