Includes
Проблема
Реализовать функцию Array.includes из JavaScript в системе типов TypeScript.
Этот тип принимает два тип параметра. Результатом должно быть либо true, либо
false. Например:
// expected to be `false`
type isPillarMen = Includes<["Kars", "Esidisi", "Wamuu", "Santana"], "Dio">;
Решение
Начнём с типа, который принимает два тип параметра: T (кортеж из элементов) и
U (что мы ищем в кортеже).
type Includes<T, U> = never;
Прежде чем приступить к поиску в кортеже, облегчим себе жизнь и приведём кортеж
в объединение элементов. Для этого воспользуемся индексными типами. Используя
индексные типы, мы можем написать конструкцию T[number], результатом которой
будет объединение элементов из кортежа 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];
На этом этапе, у нас есть объединение элементов из кортежа T. Как же
проверить, что элемент существует в объединении? Дистрибутивные условные типы!
Напишем условный тип для T[number] и TypeScript проверит наше условие по
отношению к каждому элементу из объединения.
Например, если мы напишем 2 extends 1 | 2, то TypeScript выполнит две проверки
2 extends 1 и 2 extends 2. Проверим, что элемент, который мы ищем [U],
находится в объединении элементов T. В случае, элемент находится в объединении
элементов, мы возвращаем true, иначе - false.
type Includes<T extends unknown[], U> = U extends T[number] ? true : false;
Комментарии