Zip
Завдання
У цьому завданні ви повинні реалізувати тип Zip<T, U>
, де T
і U
мають бути
Tuple
:
// expected to be [[1, true], [2, false]]
type R = Zip<[1, 2], [true, false]>;
Розв’язок
Почнемо з порожнього типу, який ми будемо використовувати для реалізації.
Тип-параметр T
використовується, щоб отримати перший кортеж, який нам потрібно
з’єднати, а U
- другий:
type Zip<T, U> = any;
Перш ніж приступити до реалізації, дозвольте мені навести вам приклад того, що
тут означає з’єднати. Наприклад, якщо у вас є кортеж [1, 2]
і кортеж
[true, false]
, вам потрібно об’єднати перші елементи кортежу в новий кортеж -
[1, true]
. Потім зробити те ж саме, але з другими - [2, false]
. Зрештою,
помістіть ці кортежі в інший кортеж - [[1, true], [2, false]]
. Ось що означає
з’єднати.
Як бачите, нам потрібно мати можливість отримати перший елемент кортежу. Ми
можемо зробити це за допомогою виведення! Візьмемо перший кортеж T
і виведемо
з нього елемент (TI
) та хвіст (TT
):
type Zip<T, U> = T extends [infer TI, ...infer TT] ? never : never;
Але у нас є ще один кортеж, який ми не врахували. Тож робимо те саме для U
—
виводимо елемент (UI
) й хвіст (UT
):
type Zip<T, U> = T extends [infer TI, ...infer TT]
? U extends [infer UI, ...infer UT]
? never
: never
: never;
Якщо в обох кортежах є елемент і хвіст, ми можемо з’єднати їх разом. Для цього
ми повертаємо кортеж із TI
і UI
:
type Zip<T, U> = T extends [infer TI, ...infer TT]
? U extends [infer UI, ...infer UT]
? [TI, UI]
: never
: never;
Проблема в тому, що ми не обробляємо інші елементи. Ми просто отримуємо один
кортеж, і все. Щоб вирішити це, нам потрібно знову викликати Zip
з хвостами
кортежів. Крім того, не забувайте, що нам потрібен кортеж з кортежів, тому ми
знову загортаємо його в квадратні дужки:
type Zip<T, U> = T extends [infer TI, ...infer TT]
? U extends [infer UI, ...infer UT]
? [[TI, UI], Zip<TT, UT>]
: never
: never;
Добре мати тип, який можна викликати рекурсивно. Але використовуючи тип Zip
,
ми отримуємо в кінці кортеж кортежів, який опиняється всередині нашого кортежу
кортежів. Нам це не потрібно. Тож розгортаємо результат виклику Zip
:
type Zip<T, U> = T extends [infer TI, ...infer TT]
? U extends [infer UI, ...infer UT]
? [[TI, UI], ...Zip<TT, UT>]
: never
: never;
Останнє питання, на яке потрібно відповісти - що робити, коли хвоста більше
немає? Замість того, щоб повертати тип never
, ми можемо повернути лише
порожній кортеж, щоб не зламати рекурсивний виклик.
type Zip<T, U> = T extends [infer TI, ...infer TT]
? U extends [infer UI, ...infer UT]
? [[TI, UI], ...Zip<TT, UT>]
: []
: [];
Коментарі