StartsWith
Завдання
Реалізуйте StartsWith<T, U>
, який приймає два рядкові типи і повертає - чи
починається T
з U
. Наприклад:
type a = StartsWith<"abc", "ac">; // expected to be false
type b = StartsWith<"abc", "ab">; // expected to be true
type c = StartsWith<"abc", "abcd">; // expected to be false
Розв’язок
Знаючи про рядкові тип-літерали у TypeScript, рішення стає досить очевидним. Почнемо з порожнього типу:
type StartsWith<T, U> = any;
Нам потрібно перевірити, чи вхідний тип-параметр T
починається з рядкового
літералу U
. Я зроблю простіше і просто перевірю, чи T
є U
, використовуючи
умовні типи:
type StartsWith<T, U> = T extends `${U}` ? never : never;
Якщо вхідний тип-параметр T
такий самий, як тип-параметр U
, ми потрапимо до
правдивої гілки умовного типу. Але нам не потрібно, щоб вони були рівними. Нам
потрібно перевірити, чи він починається з U
. Іншими словами; нам байдуже, чи
буде щось після U
. Тому використовуємо там тип any
:
type StartsWith<T, U> = T extends `${U}${any}` ? never : never;
Якщо тип T
відповідає шаблону, який починається з U
, ми повертаємо тип
true
. В іншому випадку - false
:
type StartsWith<T, U> = T extends `${U}${any}` ? true : false;
Ми пройшли всі тести, але отримали помилку компіляції: “Type ‘U’ is not
assignable to type ‘string | number | bigint | boolean | null | undefined’.“. Це
тому, що ми не додали обмеження над тип-параметром, яке вказує, що U
- рядок.
Давайте додамо:
type StartsWith<T, U extends string> = T extends `${U}${any}` ? true : false;
Коментарі