Unique
Завдання
Реалізуйте типізовану версію Lodash.uniq()
. Unique<T>
приймає масив T
, й
повертає його без повторюваних значень.
type Res = Unique<[1, 1, 2, 2, 3, 3]>; // expected to be [1, 2, 3]
type Res1 = Unique<[1, 2, 3, 4, 4, 5, 6, 7]>; // expected to be [1, 2, 3, 4, 5, 6, 7]
type Res2 = Unique<[1, "a", 2, "b", 2, "a"]>; // expected to be [1, "a", 2, "b"]
Розв’язок
У цьому завданні нам потрібно реалізувати lodash-версію функції .uniq()
у
системі типів. Наш тип повинен приймати єдиний тип-параметр, який є кортежем
елементів. Нам потрібно відфільтрувати дублікати звідти та залишити лише
унікальні елементи.
Почну з порожнього типу:
type Unique<T> = any;
Щоб перевірити, чи є елемент унікальним у кортежі, спочатку нам потрібно його дістати. Для цього ми будемо використовувати виведення в умовних типах.
Однак ми зробимо це у зворотному порядку. Зверніть увагу на порядок унікальних
елементів в очікуваному результаті. Якщо ми напишемо [infer H, ...infer T]
,
наш кінцевий результат буде не в правильному порядку. Отже, я спочатку дістаю
останній елемент кортежу:
type Unique<T> = T extends [...infer H, infer T] ? never : never;
Тепер, маючи елемент у тип-параметрі T
, що ми повинні перевірити? Ми повинні
перевірити, чи присутній елемент T
в іншій частині кортежу H
:
type Unique<T> = T extends [...infer H, infer T]
? T extends H[number]
? never
: never
: never;
Маючи умовний тип T extends H[number]
, ми можемо перевірити, чи присутній тип
T
в об’єднанні елементів H
. Якщо так, це означає, що T
є дублікатом і його
потрібно пропустити. Тобто ми просто повертаємо все, що залишилося в H
:
type Unique<T> = T extends [...infer H, infer T]
? T extends H[number]
? [...Unique<H>]
: never
: never;
Але якщо його немає в H
- це унікальний елемент! У цьому випадку ми включаємо
T
в кортеж:
type Unique<T> = T extends [...infer H, infer T]
? T extends H[number]
? [...Unique<H>]
: [...Unique<H>, T]
: never;
Останній випадок – це коли вхідний тип-параметр T
не кортеж. Тут ми просто
повертаємо порожній кортеж, щоб не зламати рекурсивний виклик:
type Unique<T> = T extends [...infer H, infer T]
? T extends H[number]
? [...Unique<H>]
: [...Unique<H>, T]
: [];
Таким чином ми реалізували тип, який може повертати кортеж з унікальними елементами в ньому.
Коментарі