ジェネリクス (generics)とは
TypeScriptで重要な文法/機能の一つ、日本語だと「総称型」
抽象的な型のテンプレートを用意し、実体を作る時に具体化する。
つまり動的に型を設定する事が出来るという事。
この機能によって様々なユースケースで共通化が楽にでき、型エイリアス、Class、関数コンポーネントでも使えます。
このジェネリクスを用いた共通化に関して、TypeScript公式で詳しく書かれていました、以下抜粋。
型の安全性とコードの共通化の両立は難しいものです。
あらゆる型で同じコードを使おうとすると、型の安全性が犠牲になります。
逆に、型の安全性を重視しようとすると、同じようなコードを量産する必要が出てコードの共通化が達成しづらくなります。
こうした問題を解決するために導入された言語機能がジェネリクスです。
ジェネリクスを用いると、型の安全性とコードの共通化を両立することができます。
ジェネリクスが解決する問題
ジェネリクスが具体的にどのような問題を解決するのか見ていきましょう。ここに、chooseRandomlyString()という普通の関数があります。この関数は、2つの文字列を引数に受け取り、五分五分の確率で第1引数か第2引数の値を抽選して返します。
function chooseRandomly<String>(v1: <string>, v2: <string>): <string> {
return Math.random() <= 0.5 ? v1 : v2;
}
この関数では、引数が数値、URLオブジェクトなどのユースケースに対応できない、以下のように複製させるとコード量が増えて管理が面倒になる。
function chooseRandomly<Number>(v1: <number>, v2: <number>): <number> {
return Math.random() <= 0.5 ? v1 : v2;
}
そこでジェネリクスを使い、以下の様に型の安全性を維持しながら、コードを共通化します。
function chooseRandomly<T>(v1: T, v2: T): T {
return Math.random() <= 0.5 ? v1 : v2;
}
<T>
は型変数名の定義です。慣習としてTがよく使われますが、AでもTypeでも構いません。
関数の引数の型や戻り値の型として書かれたTは型変数を参照しています。
ジェネリクスはコードの共通化と型の安全性を両立してくれる言語機能です。
汎用的なコードをさまざまな型で使えるようにしたい際、ジェネリクスを使う。
anyとの違い
型をanyにしてしまう問題点は、戻り値の型もanyになってしまうため、コンパイラのチェックが行われなくなり、バグを生みやすくなることです。つまり、型の安全性が損なわれるということです。
まとめ
• コードの共通化すると、型の安全性が弱まる。
• 型の安全性を高めると、コードの共通化が難しくなる。
• ジェネリクスは、コードの共通化と型の安全性を両立するための言語機能。
• ジェネリクスは、型も引数のように扱うという発想。