お題
配列T
を受け取り、その最初の要素を返す型First
を実装する。
やりたいこと
type arr = ["a", "b", "c"]
type result = First<arr> // => "a"
解答
type First<T extends any[]> = T extends [infer U, ...any[]] ? U : never;
解説
処理の流れ
-
<T extends any[]>
Tを配列のみ受け取るように制約。 -
T extends [infer U, ...any[]] ? ...
条件分岐(T
が[infer U, ...any[]]
の形だったら...)で評価を行う。 -
[infer U, ...any[]]
-
infer U
要素の最初の要素の型推論を行う。 -
...any[]
配列の残りの要素を表す。
-
-
... ? U : never
最初の要素があればU
、なければnever
を返す。
Conditional Types(型の条件分岐)とは...
- 条件によって型を決めることができる。
- 三項演算子で記述する。
-
extends
の記述が必要
T extends U ? X : Y;
// trueならX、falseならY
type IsString<T> = T extends string ? true : false;
type IsString<"a"> // => true;
inferとは...
-
infer
は型推論を行う(inferの直訳は推論)。
型の中から必要な部分を取り出して名前をつける」ための道具。 -
extends
の右辺にのみ記述が可能。
なぜ型推論をして、具体的な値("a"や0)を抽出できるのか?
TypeSciptは型推論の際に、可能な限り具体的な型推論を行うから。
["a", "b", "c"]
の配列の最初の要素は明確に"a"
という文字列
→ 型としてstring
よりも具体的な"a"
という文字リテラル型が推論される。
残余パターン(...)とは...
- 省略して書いてるイメージ
-
[infer U, ...any[]]
の部分は、「最初の要素の型をUとして推論し、残りは何でも良い」という意味合いを持つ。
参考記事
Conditional Types
infer
- infer | TypeScript入門『サバイバルTypeScript』
- TypeScriptのinferを今度こそちゃんと理解する | Zenn
- 配列の最初の要素を返す型を作ろう | mosya-TC
残余パターン
今回の問題