概要: このチュートリアルでは、型を形式パラメータとして使用できる TypeScript ジェネリクスについて学びます。
TypeScript ジェネリクスの紹介
TypeScript ジェネリクスを使用すると、関数、クラス、およびインターフェースの再利用可能で汎用的な形式を記述できます。このチュートリアルでは、ジェネリック関数の開発に焦点を当てます。
簡単な例を通して TypeScript ジェネリクスを説明する方が簡単でしょう。
数値の配列から乱数を返す関数を開発する必要があると仮定します。
次のgetRandomNumberElement()
関数は、数値の配列をパラメータとして受け取り、配列からランダムな要素を返します。
function getRandomNumberElement(items: number[]): number {
let randomIndex = Math.floor(Math.random() * items.length);
return items[randomIndex];
}
Code language: TypeScript (typescript)
配列のランダムな要素を取得するには、次の手順が必要です。
- 最初にランダムなインデックスを見つけます。
- ランダムなインデックスに基づいてランダムな要素を取得します。
配列のランダムなインデックスを見つけるには、0〜1の間の乱数を返すMath.random()
を使用し、配列の長さを掛けて、結果にMath.floor()
を適用します。
次に、getRandomNumberElement()
関数の使用方法を示します。
let numbers = [1, 5, 7, 4, 2, 9];
console.log(getRandomNumberElement(numbers));
Code language: TypeScript (typescript)
文字列の配列からランダムな要素を取得する必要があると仮定します。今回は、新しい関数を作成することになります。
function getRandomStringElement(items: string[]): string {
let randomIndex = Math.floor(Math.random() * items.length);
return items[randomIndex];
}
Code language: TypeScript (typescript)
getRandomStringElement()
関数のロジックは、getRandomNumberElement()
関数と同じです。
この例は、getRandomStringElement()
関数の使用方法を示しています。
let colors = ['red', 'green', 'blue'];
console.log(getRandomStringElement(colors));
Code language: TypeScript (typescript)
後で、オブジェクトの配列からランダムな要素を取得する必要が生じる可能性があります。新しい配列型からランダムな要素を取得するたびに新しい関数を作成することは、拡張性がありません。
任意の型の使用
この問題に対処する1つの方法は、配列引数の型をany[]
に設定することです。これにより、any
型の配列で機能する1つの関数を記述する必要があります。
function getRandomAnyElement(items: any[]): any {
let randomIndex = Math.floor(Math.random() * items.length);
return items[randomIndex];
}
Code language: TypeScript (typescript)
getRandomAnyElement()
は、数値、文字列、オブジェクトなどを含むany
型の配列で機能します。
let numbers = [1, 5, 7, 4, 2, 9];
let colors = ['red', 'green', 'blue'];
console.log(getRandomAnyElement(numbers));
console.log(getRandomAnyElement(colors));
Code language: TypeScript (typescript)
このオプションは問題なく機能しますが、欠点があります。それは、返される要素の型を強制できないということです。言い換えれば、型安全ではありません。
コードの重複を避けながら型を保持するためのより良い解決策は、ジェネリクスを使用することです。
TypeScript ジェネリクスが役に立ちます
次に、型T
の配列からランダムな要素を返すジェネリック関数を示します。
function getRandomElement<T>(items: T[]): T {
let randomIndex = Math.floor(Math.random() * items.length);
return items[randomIndex];
}
Code language: TypeScript (typescript)
この関数は型変数T
を使用します。T
を使用すると、関数を呼び出すときに提供された型をキャプチャできます。さらに、関数はT
型変数を戻り値の型として使用します。
このgetRandomElement()
関数は、文字列、数値、オブジェクトなどを含む任意のデータ型で機能できるため、ジェネリックです。
慣例により、型変数として文字T
を使用します。ただし、A
、B
、C
などの他の文字を自由に使用できます。
ジェネリック関数の呼び出し
次に、数値の配列でgetRandomElement()
を使用する方法を示します。
let numbers = [1, 5, 7, 4, 2, 9];
let randomEle = getRandomElement<number>(numbers);
console.log(randomEle);
Code language: TypeScript (typescript)
この例では、number
をT
型としてgetRandomElement()
関数に明示的に渡しています。
実際には、引数に対して型推論を使用します。つまり、TypeScriptコンパイラに、渡す引数の型に基づいてT
の値を自動的に設定させます。次に例を示します。
let numbers = [1, 5, 7, 4, 2, 9];
let randomEle = getRandomElement(numbers);
console.log(randomEle);
Code language: TypeScript (typescript)
この例では、number
型をgetRandomElement()
に明示的に渡しませんでした。コンパイラは引数を見て、T
をその型に設定します。
これで、getRandomElement()
関数も型安全になりました。たとえば、戻り値を文字列変数に割り当てると、エラーが発生します。
let numbers = [1, 5, 7, 4, 2, 9];
let returnElem: string;
returnElem = getRandomElement(numbers); // compiler error
Code language: TypeScript (typescript)
複数の型を持つジェネリック関数
次に、2つの型変数U
とV
を使用してジェネリック関数を開発する方法を示します。
function merge<U, V>(obj1: U, obj2: V) {
return {
...obj1,
...obj2
};
}
Code language: JavaScript (javascript)
merge()
関数は、型U
とV
の2つのオブジェクトをマージします。2つのオブジェクトのプロパティを単一のオブジェクトに結合します。
型推論は、merge()
関数の戻り値を、U
とV
の交差型であるU & V
として推論します。
次に、2つのオブジェクトをマージするmerge()
関数の使用方法を示します。
let result = merge(
{ name: 'John' },
{ jobTitle: 'Frontend Developer' }
);
console.log(result);
Code language: JavaScript (javascript)
出力
{ name: 'John', jobTitle: 'Frontend Developer' }
Code language: CSS (css)
TypeScript ジェネリクスの利点
次に、TypeScript ジェネリクスの利点を示します。
- コンパイル時に型チェックを利用できます。
- 型キャストを排除します。
- ジェネリックアルゴリズムを実装できます。
まとめ
- TypeScript ジェネリクスを使用して、再利用可能で汎用的な、型安全な関数、インターフェース、およびクラスを開発します。