mosya<TC> - 文字列から両端の空白を削除した文字列を返すTrim<T>を実装しようの解説
この記事はmosya<TC>の問題の一つであるTrim型の解説になります。
問題
文字列を受け取り、両端の空白を削除した新しい文字列を返す Trim
例えば以下のようなコードを満たすようにStringToUnion型を実装しましょう。
type trimed = Trim<" Hello World ">; // expected to be 'Hello World'
前提知識
この問題を解くにあたって型についての以下の知識を理解しておく必要があります。
Conditional Types
を理解するinfer
を理解するTemplate Literal Types
を理解する- 再帰的な型を理解する
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"
このように、文字列リテラルを使って型を作成することができます。
再帰的な型を理解する
再帰的な型は、自分自身を参照する型のことです。
例えば、以下のような型が考えられます。
type Tree<T> = {
value: T;
left: Tree<T>;
right: Tree<T>;
};
この型は、Tree
という型がvalue
というプロパティを持ち、left
とright
というプロパティはTree
型を持つという型です。
以下のような使用例が考えられます。
// 使用例
const node: Tree = {
value: 1,
left: {
value: 2,
left: null,
right: null,
},
right: {
value: 3,
left: null,
right: {
value: 4,
left: null,
right: null,
},
},
};
このように、再帰的な型は繰り返し同じ型を再利用したい場合に便利です。
解答例
以上の知識を使って、以下のように解答することができます。
type Trim<S extends string> = S extends
| `${" "}${infer R}`
| `${infer R}${" "}`
? Trim<R>
: S;
ここでポイントとなってくるのは${' '}${infer R}
という部分です。
これは空白文字とその他の文字を表し、文字列S
がこの形に当てはまる場合はinfer R
に文字列の残りの部分が当てはまります。
また、|
を使うことで、S
が空白文字で始まる場合と空白文字で終わる場合の両方の条件にマッチするかどうかで条件分岐を行っています。
例えば、' Hello World '
の場合は、' '
と'Hello World '
に分割され、'Hello World '
がinfer R
に当てはまります。
そして、この'Hello World '
の部分に対して再びTrim
を適用することで、最終的に'Hello World'
という文字列を取得することができます。
Authored by
Godai@steelydylan
Webサービスを作るのが好きなWebエンジニア。子供が産まれたことをきっかけに独立し法人化。サービス開発が大好き。
好きな言語はTypeScript。