mosya<TC> - KebabCase<T>を実装してみようの解説
この記事はmosya<TC>の問題の一つであるKebabCase型の解説になります。
問題
キャメルケースもしくはパスカルケースの文字列を、ケバブケースに置換する方を実装します。
FooBarBaz
-> foo-bar-baz
例えば以下のコードを満たすように実装しましょう。
type FooBarBaz = KebabCase<"FooBarBaz">;
const foobarbaz: FooBarBaz =
"foo-bar-baz";
type DoNothing =
KebabCase<"do-nothing">;
const doNothing: DoNothing =
"do-nothing";
解答例
type KebabCase<S> =
S extends `${infer S1}${infer S2}`
? S2 extends Uncapitalize<S2>
? `${Uncapitalize<S1>}${KebabCase<S2>}`
: `${Uncapitalize<S1>}-${KebabCase<S2>}`
: S;
まず、Sをinfer
と文字列リテラルを使って、最初の文字S1とそれ以降の文字S2に分割します。
type KebabCase<S> = S extends `${infer S1}${infer S2}` ...
次に、S2が小文字になっているかどうかを判定します。
type KebabCase<S> = S extends `${infer S1}${infer S2}`
? S2 extends Uncapitalize<S2> ...
もし小文字になっている場合は、S1
を小文字にして、S2
を再帰的に処理します。
大文字の場合は、S1
を小文字にして、S2
の前に-
をつけて、S2
を再帰的に処理します。
type KebabCase<S> = S extends `${infer S1}${infer S2}`
? S2 extends Uncapitalize<S2>
? `${Uncapitalize<S1>}${KebabCase<S2>}`
: `${Uncapitalize<S1>}-${KebabCase<S2>}`
...
これ以上、SをS1
とS2
に分割できない場合は、Sをそのまま返します。
type KebabCase<S> =
S extends `${infer S1}${infer S2}`
? S2 extends Uncapitalize<S2>
? `${Uncapitalize<S1>}${KebabCase<S2>}`
: `${Uncapitalize<S1>}-${KebabCase<S2>}`
: S;
Authored by
Godai@steelydylan
Webサービスを作るのが好きなWebエンジニア。子供が産まれたことをきっかけに独立し法人化。サービス開発が大好き。
好きな言語はTypeScript。