Trim Right
Завдання
Реалізуйте TrimRight<T>
, який приймає рядок та повертає новий рядок із
видаленими пробілами в кінці. Наприклад:
type Trimmed = TrimRight<" Hello World ">; // expected to be ' Hello World'
Розв’язок
Це завдання насправді таке саме, як Trim та Trim Left. Але цього разу нам потрібно видалити пробіли праворуч.
Ми починаємо, як зазвичай, з порожнього типу, який нам потрібно реалізувати:
type TrimRight<S extends string> = any;
Тепер, як перевірити, чи закінчується рядок пробілом? Для цього ми можемо використати умовний тип, додавши пробіл до вхідного рядка:
type TrimRight<S extends string> = S extends `${infer T} ` ? never : never;
Зверніть увагу на частину infer T
. Якщо рядок справді закінчується пробілом,
нам потрібно взяти його частину без пробілу. Отже, ми виводимо частину рядка без
нього в параметр типу T
.
Маючи частину рядка без пробілів праворуч, ми можемо повернути її:
type TrimRight<S extends string> = S extends `${infer T} ` ? T : never;
Однак у такому випадку це вирішить проблему лише для одного пробілу. А як щодо випадків, коли їх більше? Щоб покрити це, нам потрібно продовжувати їх позбуватися, доки їх не залишиться. Це легко зробити через рекурсивний виклик того самого типу:
type TrimRight<S extends string> = S extends `${infer T} `
? TrimRight<T>
: never;
Тепер наш тип буде рекурсивно видаляти пробіли один за одним, поки їх не залишиться. У такому випадку наш умовний тип перейде до помилкової гілки. Оскільки на цьому кроці ми не маємо пробілу, ми можемо повернути вхідний рядок без будь-яких змін:
type TrimRight<S extends string> = S extends `${infer T} ` ? TrimRight<T> : S;
Я думав, що це все. Але ми бачимо в тестових випадках, що є деякі помилки.
Причина в тому, що ми не обробляємо символи табуляції та нового рядка. Отже,
давайте перемістимо їх в окремий тип під назвою Whitespace
, де ми створимо
список символів:
type Whitespace = " " | "\n" | "\t";
А тепер просто замінимо наш символ на тип:
type TrimRight<S extends string> = S extends `${infer T}${Whitespace}`
? TrimRight<T>
: S;
Повне рішення з обома типами:
type Whitespace = " " | "\n" | "\t";
type TrimRight<S extends string> = S extends `${infer T}${Whitespace}`
? TrimRight<T>
: S;
Коментарі