mosya<TC> - 文字列型の最初の文字を大文字にする型を作ろうの解説
この記事はmosya<TC>の問題の一つであるCapitalize型の解説になります。
問題
文字列S
の最初の文字を大文字に変換する型MyCapitalize<S>
を実装します。
type capitalized =
MyCapitalize<"hello world">; // expected to be 'Hello world'
前提知識
Conditional Types
を理解するinfer
を理解するTemplate Literal Types
を理解するUpperCase
を理解する
Conditional Typesを理解する
Conditional Typesは、条件によって型を変更することができる機能です。
例えば、以下のような型が考えられます。
type Foo<T> = T extends string
? string
: number;
この型は、T
がstring
型を継承している場合はstring
型を、そうでない場合はnumber
型を返します。
このように、extends
を使って条件を指定することで、型を変更することができます。
inferを理解する
infer
は、型を推論することができる機能です。
例えば、以下のような型が考えられます。
type ArrayItem<T> =
T extends (infer R)[] ? R : never;
この型は、T
が配列の場合は、配列の中の型を返します。
以下のように使うことができます。
type Foo = ArrayItem<string[]>; // string
この場合、infer R
にはstring[]
型が当てはまるので、R
はstring
型に推論され、R
を返すのでstring
型が返されます。
このように推論される型を取得するのにinfer
は役立ちます。
Template Literal Typesを理解する
Template Literal Typesは、文字列リテラルを使って型を作成することができる機能です。型を組み合わせて新しい文字列の型を作成することができます。
例えば、以下のような型が考えられます。
type Foo<T> = `${T} World`;
type HelloWorld = Foo<"Hello">; // "Hello World"
このように、文字列リテラルを使って型を作成することができます。
UpperCaseを理解する
UpperCase
は、文字列を大文字に変換する型です。
例えば、以下のように利用できます。
type HELLO = Uppercase<"hello">; // "HELLO"
解答例
以上の知識を使って、以下のように解答することができます。
type MyCapitalize<S extends string> =
S extends `${infer First}${infer Rest}`
? `${Uppercase<First>}${Rest}`
: S;
まず、S
が文字列リテラルであることを制約します。
type MyCapitalize<S extends string> = ...
次に、S
をinfer
を使って分割します。最初の文字と残りの文字に分割します。もし分割できない場合はそのままS
を返します。
type MyCapitalize<S extends string> = S extends `${infer First}${infer Rest}` ? ... : S
最後に、最初の文字を大文字に変換して、残りの文字と結合して返します。
type MyCapitalize<S extends string> =
S extends `${infer First}${infer Rest}`
? `${Uppercase<First>}${Rest}`
: S;
Authored by
Godai@steelydylan
Webサービスを作るのが好きなWebエンジニア。子供が産まれたことをきっかけに独立し法人化。サービス開発が大好き。
好きな言語はTypeScript。