KebabCase
Завдання
Привести рядок до формату kebab-case
. Наприклад:
type kebabCase = KebabCase<"FooBarBaz">; // expected "foo-bar-baz"
Розв’язок
Це завдання дуже схоже з завданням “CamelCase”. Почнемо з виводу типів. Нам потрібно дізнатись перший символ рядка та решту (хвіст).
type KebabCase<S> = S extends `${infer C}${infer T}` ? never : never;
Коли тип не відповідає шаблону “перший символ та решта (хвіст)”, це означає кінець рядка. Тому повертаємо вхідний параметр без змін.
type KebabCase<S> = S extends `${infer C}${infer T}` ? never : S;
Але, коли наш шаблон спрацював, ми повинні обробити два випадки. Коли решта
рядка не має заголовного символу та навпаки, коли має. Для перевірки
використовуємо вбудований тип Uncapitalize
.
type KebabCase<S> = S extends `${infer C}${infer T}`
? T extends Uncapitalize<T>
? never
: never
: S;
Якщо решта рядка не має заголовного символу? Це означає, що в нас може бути
Foo
або foo
. Тож, ми перетворюємо перший символ в нижній регістр, а решту
рядка залишаємо без змін. Не забуваємо застосовувати цей тип рекурсивно, для
обробки наступних частин рядка.
type KebabCase<S> = S extends `${infer C}${infer T}`
? T extends Uncapitalize<T>
? `${Uncapitalize<C>}${KebabCase<T>}`
: never
: S;
Другий випадок, коли решта рядка містить заголовний символ(наприклад, fooBar
).
Перетворюємо перший символ в нижній регістр, додавши дефіс, та продовжуємо
рекурсивно обробляти рядок. Нам не потрібно застосовувати Uncapitalize
для
решти рядка, бо він буде застосований в Uncapitalize<C>
.
type KebabCase<S> = S extends `${infer C}${infer T}`
? T extends Uncapitalize<T>
? `${Uncapitalize<C>}${KebabCase<T>}`
: `${Uncapitalize<C>}-${KebabCase<T>}`
: S;
Коментарі