Завдання

Перевести рядок до CamelCase. Наприклад:

type camelCased = CamelCase<"foo-bar-baz">; // expected "fooBarBaz"

Розв’язок

Спільною частиною, яку ми можемо використати для виведення рядка є дефіс. Давайте виведемо частини до та після дефісу.

type CamelCase<S> = S extends `${infer H}-${infer T}` ? never : never;

Якщо такого шаблону немає - повертаємо рядок без змін.

type CamelCase<S> = S extends `${infer H}-${infer T}` ? never : S;

Але коли такий шаблон знайдений нам потрібно видалити дефіс та зробити першу букву великою. Крім цього не забуваємо, що можуть бути інші під-рядки, які також потрібно обробити. Зробимо це рекурсивно.

type CamelCase<S> = S extends `${infer H}-${infer T}`
  ? `${H}${CamelCase<Capitalize<T>>}`
  : S;

Тепер проблема в тому, що ми не враховуємо випадок, коли друга частина рядка уже починається з великої літери. Виправимо це перевіркою чи можемо ми присвоїти цю частину до неї ж, але капіталізованої.

type CamelCase<S> = S extends `${infer H}-${infer T}`
  ? T extends Capitalize<T>
    ? never
    : `${H}${CamelCase<Capitalize<T>>}`
  : S;

Що робити, якщо друга частина рядка уже починається з великої літери? Збережемо дефіс та пропустимо цю частину. Звісно, також рекурсивно.

type CamelCase<S> = S extends `${infer H}-${infer T}`
  ? T extends Capitalize<T>
    ? `${H}-${CamelCase<T>}`
    : `${H}${CamelCase<Capitalize<T>>}`
  : S;

Чудово, ми отримали тип, що приводить шаблонні літерали до “camelCase”!

Посилання