mosya

mosya<TC> - 文字列型の最初の文字を大文字にする型を作ろうの解説

この記事はmosya<TC>の問題の一つであるCapitalize型の解説になります。

問題

文字列Sの最初の文字を大文字に変換する型MyCapitalize<S>を実装します。

type capitalized =
  MyCapitalize<"hello world">; // expected to be 'Hello world'

前提知識

  1. Conditional Typesを理解する
  2. inferを理解する
  3. Template Literal Typesを理解する
  4. UpperCaseを理解する

Conditional Typesを理解する

Conditional Typesは、条件によって型を変更することができる機能です。

例えば、以下のような型が考えられます。

type Foo<T> = T extends string
  ? string
  : number;

この型は、Tstring型を継承している場合はstring型を、そうでない場合はnumber型を返します。

このように、extendsを使って条件を指定することで、型を変更することができます。

inferを理解する

inferは、型を推論することができる機能です。

例えば、以下のような型が考えられます。

type ArrayItem<T> =
  T extends (infer R)[] ? R : never;

この型は、Tが配列の場合は、配列の中の型を返します。

以下のように使うことができます。

type Foo = ArrayItem<string[]>; // string

この場合、infer Rにはstring[]型が当てはまるので、Rstring型に推論され、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> = ...

次に、Sinferを使って分割します。最初の文字と残りの文字に分割します。もし分割できない場合はそのまま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。

ReactやTypeScriptなどの周辺技術が学べる
オンライン学習サービスを作りました!

詳しくはこちら
mosya

mosyaはオンラインでHTML,CSS,JavaScriptを基本から学習できるサービスです。現役エンジニアが作成した豊富なカリキュラムに沿って学習を進めましょう。

© 2023 - mosya. All rights reserved.