TypeScriptのジェネリックの使い方について

16507 ワード

TypeScriptのジェネリックの使い方について

ジェネリック型パラメーターとは?

複数の場所で型レベルの制約を強制するために使われるプレースホルダーの型です。多層型パラメーターとも言われます。

実装例①(単体のジェネリック型を使用したケース)

type Filter = {
 //※<T>は、単なる慣例であるため、代わりに任意の名前を使用することもできます。
 <T>(array: T[], func: (item: T) => boolean): T[]
}

const filter: Filter = (array, func) => {
   const newArray = array.filter((item) => (
     func(item)
   ))
   return newArray
};

//「T」はnumber型になります(2より小さい値のみにフィルタリング)
filter([1, 2, 3], _ => _ > 2)

//「T」はstring型になります(bでない値のみにフィルタリング)
filter(['a', 'b', 'c'], _ => _!== 'b')

上記で行っていることを整理すると以下のようになります。

  • まず上記のfilter関数は、ジェネリック型パラメーター<T>を使用することで<T>の部分に入る型をTypeScriptに推論させて、型を制約させるように定義しています。

  • filter関数を呼び出した際の型定義として、Filter型で定義した型(ジェネリック型パラメーター)が読み込まれ、引数の値に応じてTypeScriptが型を推論し、推論した型で置き換えられます。

  • filter関数の処理が実行され、それぞれ以下の返り値が返却される

// 返り値は、2より小さい値のみにフィルタリングされるので[3]となる
filter([1, 2, 3], _ => _ > 2)

// 返り値は、bでない値のみにフィルタリングされるので["a", "c"]となる
filter(['a', 'b'], _ => _!== 'b')

実装例②(複数のジェネリック型を使用したケース)

type Map = {
  <T, U>(array: T[], func: (item: T) => U): U[]
}

const map: Map = (array, func) =>{
  const newArray = array.map((item) => (
    func(item)
  ))
  return newArray
};

map([1, 2, 3], _ =>  String(_ + "回目")

上記で行っていることを整理すると以下のようになります。

  • まず上記のmap関数は、ジェネリック型パラメーター<T>と<U>を使用することで<T>と<U>の部分に入る型をTypeScriptに推論させて、型を制約させるように定義しています。

  • map関数を呼び出した際の型定義として、Map型で定義した型(ジェネリック型パラメーター)が読み込まれ、引数の値に応じてTypeScriptが型を推論し、推論した型で置き換えられます。

  • map関数の処理が実行され、それぞれ以下の返り値が返却される

// 返り値は、Number型配列からString型配列の["1回目", "2回目", "3回目"]となる
map([1, 2, 3], _ =>  String(_ + "回目")

どこでジェネリックを宣言できるか?

以下のようなパターンでジェネリックを宣言することができます。

パターン1

Tのスコープが個々のシグネチャに限られる、完全な呼び出しシグネチャ。 Tのスコープは1つのシグネチャに限られるので、Filter型の関数を呼び出すタイミングで、Tを具体的な型にセットします。

type Filter ={
  <T>(array: T[], func:(item: T) => boolean): T[]
}

// 省略形の書き方
type Filter = <T>(array: T[], func:(item: T) => boolean): T[]

パターン2

Tのスコープがシグネチャ全体に及ぶ、完全な呼び出しシグネチャ。 Tは(特定のシグネチャの型の一部としてではなく)Filterの型の一部として宣言されているので、Filter型の関数を宣言したタイミングで、Tを具体的な型にセットします。

type Filter<T> ={
  <T>(array: T[], func:(item: T) => boolean): T[]
}
	  
// 省略形の書き方	  
type Filter<T> = <T>(array: T[], func:(item: T) => boolean): T[]

パターン3

名前付き関数の呼び出しシグネチャ。 Tのスコープはそのシグネチャに限られます。filter関数を呼び出すタイミングで、 Tを具体的な型にセットします。

function filter<T>(array: T[], func:(item: T) => boolean): T[]

参考書籍