復習:配列の最初の要素を取得する(TC-4)
お題
配列T
を受け取り、その最初の要素を返す型を実装する。
やりたいこと(具体)
type arr = ["a", "b", "c"]
type result = First<arr>
// result => "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として推論し、残りは何でも良い」という意味合いを持つ。下記のような使い方もできる。
const list = ["Japan", "China", "Korea"]
const NewList = [...list, "France"]
// NewList => ["Japan", "China", "Korea", "France"]
参考記事
Conditional Types
https://typescriptbook.jp/reference/type-reuse/conditional-types
https://zenn.dev/brachio_takumi/articles/464106a6a80eca8ab919