ジェネリクス概要
クラス、関数、インターフェースに対して後から特定の型を指定できる。
- クラス
クラスにジェネリクスを定義する場合クラスの後に<T>を記述
// valueとgetValueの戻り値型はインスタンス定義時に指定できるようにする
// 型引数(抽象的な型)後から型を定義できる
class MyClass<T>{
val!:T;
getValue():T{
return this.val;
}
}
// インスタンス作成時に型引数を指定
// 型引数に「string」を指定
let valA = new MyClass<string>();
valA.val='AAA';
// number型で定義
let valB = new MyClass<number>();
valB.val = 4;
- 関数の場合
関数名の後に<T>を記述
// 関数定義時には引数、戻り値を型引数Tとしておき、実行時に型指定できるようにする。
function test<T>(val:T):T{
return val;
}
// test実行時に型引数を指定する
console.log(test<number>(3));
console.log(test<string>('テスト'));
// アロー関数の場合の定義
let test2 = <T>(val:T):T => {
return val;
}
- インターフェースの場合
// プロパティの型を型引数Tとしておき、定義時に型指定できるようにする。
interface IntA<T> {
name:string;
val: T;
}
// 代入時にvalの型を指定
let obj: IntA<number> = { name: "よしお", val: 32 };
// 代入時にvalの型を指定
let obj2: IntA<String> = { name: "よしみつ", val: '57歳' };
型引数を複数指定
型引数指定時に「,」で複数指定できる
// 引数の型引数を複数指定
function test<T, R>(val:T, arg:R):string{
return `${val}と${arg}`;
}
// 実行時にそれぞれの型引数を指定する
console.log( test<string, number>('文字列',55) );//文字列と55
型引数の規定値
型引数を指定しなかった場合には規定値を指定できる/<T=string>
// クラスにジェネリクスを定義する場合クラスの後に<T>を記述
// MyClassには型引数を2種類(T,R)指定、Rを指定しなかった場合はboolean|numberになる
class MyClass<T, R = boolean|number>{
val!:T|R;//valはTまたはR型で定義
getValue():T|R{
return this.val;
}
}
// Tをstring型で定義、Rをnumber型で定義
let valA = new MyClass<string, number>();
valA.val='AAA';
valA.val=3;
// Tをnumber型で定義、Rは未設定(規定値のboolean|numberになる)
let valB = new MyClass<string>();
valB.val = 4;
valB.val = true;
valB.val = '文字列';
型引数に制約をつける
実行時に渡す型引数を特定の型にしたいときに
// name,ageを持つ型を指定
interface IntA {
name:string;
age: number;
}
// 引数の型は後で指定できるがIntAを満たす型のみに絞る
function getName<T extends IntA>(arg:T):string{
return `名前:${arg.name}、${arg.age}歳`;
}
// name、ageプロパティがあるので実行可能
console.log( getName( {name:'よしお', age:21, area:'関東'} ) );//名前:よしお、21歳
// ageがないためエラーとなる
// console.log( getName( {name:'よしお'} ) );
```