Завдання

Реалізуйте тип, який приймає масив й повертає його плоску версію. Наприклад:

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];

Посилання