Includes
Завдання
Реалізувати функцію JavaScript Array.includes
в системі типів. Тип приймає два
аргументи. Результат повинен бути true
або false
.
Наприклад:
// expected to be `false`
type isPillarMen = Includes<["Kars", "Esidisi", "Wamuu", "Santana"], "Dio">;
Розв’язок
Почнемо з того, що створимо тип, який приймає два аргументи: T
(кортеж із
елементів) та U
(елемент, який ми шукаємо):
type Includes<T, U> = never;
Перед тим, як шукати щось у кортежі, легше “перетворити” його на об’єднання
елементів. Для цього використаємо індексні типи. Якщо ми напишемо конструкцію
T[number]
, TypeScript поверне об’єднання усіх елементів з T
. Тобто, якщо
маємо T = [1, 2, 3]
то доступ через T[number]
поверне 1 | 2 | 3
.
type Includes<T, U> = T[number];
Але в такому випадку ми отримаємо помилку “Type ‘number’ cannot be used to index
type ‘T’”. Це тому що у нас немає жодних обмежень для T
. Потрібно сказати
TypeScript-у, що T
- це масив.
type Includes<T extends unknown[], U> = T[number];
Маємо об’єднання елементів. Як перевірити чи елемент існує в цьому об’єднанні? Дистрибутивні (розподілені) умовні типи! Ми можемо написати умовний тип для об’єднання і TypeScript автоматично застосує цю умову до кожного елементу об’єднання.
Тобто якщо ви напишете 2 extends 1 | 2
, TypeScript насправді замінить це двома
умовами 2 extends 1
та 2 extends 2
.
Використаємо це, щоб перевірити чи є U
у T[number]
і, якщо так, повернемо
true
.
type Includes<T extends unknown[], U> = U extends T[number] ? true : false;
Коментарі