演習 - インターフェイスとクラスでジェネリックを実装する
ジェネリックは、型をコンポーネントに渡す方法にすぎません。このため、ネイティブ型をジェネリック型変数だけでなく、インターフェイス、関数、クラスにも適用できます。 このユニットでは、これらの複合型でジェネリックを使用するいくつかの方法を確認します。
インターフェイス、関数、クラスでジェネリックを使用してみることにしましょう。 すべてのサンプル コードは、基本的に同じタスクを、異なる手法を使用して実行します。
ジェネリック インターフェイスを宣言する
型の注釈を型変数に置き換えることによって、インターフェイス宣言でジェネリックを使用することができます。
プレイグラウンドを開いて、既存のコードをすべて削除します。
2 つのプロパティ
value
とmessage
を持ち、プロパティの型に 2 つのジェネリック型変数T
とU
を使用する、Identity
という名前の単純なインターフェイスを宣言します。interface Identity<T, U> { value: T; message: U; }
Identity
インターフェイスをオブジェクト型として使用して、2 つの変数を宣言します。let returnNumber: Identity<number, string> = { value: 25, message: 'Hello!' } let returnString: Identity<string, number> = { value: 'Hello!', message: 25 }
ジェネリック インターフェイスを関数型として宣言する
ジェネリック インターフェイスを関数型として宣言することもできます。
プレイグラウンドで作業を続けます。
メソッドのジェネリック シグネチャ
(value: T, message: U): T
を含む、ProcessIdentity
という名前のジェネリック インターフェイスを宣言します。 メソッドには名前がないことに注意してください。 これにより、型シグネチャが一致する任意の関数に適用することができます。interface ProcessIdentity<T, U> { (value: T, message: U): T; }
ProcessIdentity
インターフェイスと同じ型シグネチャを持つ、processIdentity
という名前の関数を宣言します。function processIdentity<T, U> (value: T, message: U) : T { console.log(message); return value }
変数の型として
ProcessIdentity
インターフェイスを使用する、processor
という名前の関数型変数を宣言し、型T
の場合はnumber
を、型U
の場合はstring
を渡します。 次に、processIdentity
関数をこれに割り当てます。 以上で、この変数を関数としてコードで使用できるようになり、TypeScript によって、この型が検証されます。let processor: ProcessIdentity<number, string> = processIdentity; let returnNumber1 = processor(100, 'Hello!'); // OK let returnString1 = processor('Hello!', 100); // Type check error
ジェネリック インターフェイスをクラス型として宣言する
ジェネリック インターフェイスを宣言し、クラスに実装することもできます。
プレイグラウンドで作業を続けます。
2 つのプロパティ
value
とmessage
を持ち、プロパティの型に 2 つのジェネリック型変数T
とU
を使用する、ProcessIdentity
という名前のインターフェイスを宣言します。 次に、型T
の値を返す、process
という名前のメソッドのジェネリック シグネチャを追加します。interface ProcessIdentity<T, U> { value: T; message: U; process(): T; }
ProcessIdentity
インターフェイスを実装する、processIdentity
という名前のジェネリック クラスを定義します。 ここでは、processIdentity
クラスの変数の型に、X
およびY
という名前を付けます。 型の値はチェーンを介して伝播され、変数名は重要ではないため、インターフェイスとクラスで異なる変数名を使用することができます。class processIdentity<X, Y> implements ProcessIdentity<X, Y> { value: X; message: Y; constructor(val: X, msg: Y) { this.value = val; this.message = msg; } process() : X { console.log(this.message); return this.value } }
新しい変数を宣言し、それに新しい
processIdentity
オブジェクトを割り当てて、変数の型X
とY
にnumber
とstring
を渡し、引数の値としてnumber
とstring
を渡します。let processor = new processIdentity<number, string>(100, 'Hello'); processor.process(); // Displays 'Hello' processor.value = '100'; // Type check error
ジェネリック クラスを定義する
インターフェイスを使用せずにジェネリック クラスを宣言することもできます。 次の例では、ProcessIdentity
インターフェイスを実装せずに、processIdentity
をジェネリック クラスとして宣言します。
class processIdentity<T, U> {
private _value: T;
private _message: U;
constructor(value: T, message: U) {
this._value = value;
this._message = message;
}
getIdentity() : T {
console.log(this._message);
return this._value
}
}
let processor = new processIdentity<number, string>(100, 'Hello');
processor.getIdentity(); // Displays 'Hello'