mosya
mosya Business はこちら

mosya<TC> - Last型を実装して配列の最後の要素の型を取得しようの解説

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

問題

配列 T を受け取り、その最後の要素の型を返す汎用的な Last を実装してください。

type arr1 = ["a", "b", "c"];
type arr2 = [3, 2, 1];

type tail1 = Last<arr1>; // expected to be 'c'
type tail2 = Last<arr2>; // expected to be 1

前提知識

この問題を解くにあたって型についての以下の知識を理解しておく必要があります。

  1. Conditional Typesを理解する
  2. inferを理解する
  3. スプレッド演算子を理解する

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は役立ちます。

スプレッド演算子を理解する

スプレッド演算子...は、配列やオブジェクトの中身を展開する演算子です。
これを使うと配列やオブジェクトの中身を展開して、新しい配列やオブジェクトを生成することができます。
実際の値だけでなく型にもこの演算子を使うことができます。

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

type Foo = [1, 2, 3];

type Bar = [...Foo, 4]; // [1, 2, 3, 4]

解答例

type Last<T extends any[]> = T extends [
  ...any[],
  infer U
]
  ? U
  : never;

今回は、Tが配列であることが条件なので、T extends any[]という条件を指定します。
そして、配列の中の要素を返すには推論のためのinferと条件のためのextends構文を組み合わせます。
スプレッド演算子を使うことで、配列の最後以外の要素を、...で配列として取得し、最後の要素を推論させたいので、inferを使ってUという名前で受け取ります。
そして、extendsを使って、条件分岐でUを返すことで、最後の要素の型を返すことができます。

Authored by

筆者の写真

Godai@steelydylan

Webサービスを作るのが好きなWebエンジニア。子供が産まれたことをきっかけに独立し法人化。サービス開発が大好き。
好きな言語はTypeScript。

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

詳しくはこちら
mosya

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

© 2023 - mosya. All rights reserved.