Проблема

Реализуйте тип, который принимает массив и возвращает его плоскую версию. Например:

type flatten = Flatten<[1, 2, [3, 4], [[[5]]]> // [1, 2, 3, 4, 5]

Решение

Начнем со случаев попроще. Когда получаем пустой массив, возвращаем пустой массив, так как он и так плоский, с ним ничего не нужно делать. Иначе, вернём сам T (пока что):

type Flatten<T> = T extends [] ? [] : T;

Но, что если T будет не пустым массивом? Это значит, что у нас массив с элементами внутри или сам элемент из массива. Если работаем с массивом из элементов, выводим один элемент из него и остальную часть. После вывода, возвращаем новый массив, с выведенными элементами.

type Flatten<T> = T extends []
  ? []
  : T extends [infer H, ...infer T]
  ? [H, T]
  : [T];

Кстати, обратите внимание, что в случае, если у нас не пустой массив и не массив с элементами, то ожидаем что это элемент из массива. В таком случае, возвращаем этот элемент в кортеже.

Имея выведенные типы из массива, мы можем рекурсивно вызывать Flatten снова и снова и передавать в него эти выведенные типы. Таким образом, заходим вглубь массива до тех пор, пока не дойдем до элемента. И как только получили этот элемент, возвращаем его как базовый случай [T].

В результате, получаем тип, который рекурсивно обходит каждый элемент и возвращает вместо него кортеж из одного элемента. Благодаря вариативным типам, эти кортежи сливаются в один, который и даёт нам плоский массив.

type Flatten<T> = T extends []
  ? []
  : T extends [infer H, ...infer T]
  ? [...Flatten<H>, ...Flatten<T>]
  : [T];

Что почитать