BracketsでTypeScriptのジェネリック型パラメーターを操る!サンプルコードで理解を深める
TypeScript におけるクラスの角度括弧 (<>) 構文
ジェネリック型パラメーターとは?
ジェネリック型パラメーターは、クラスが特定の型を持つ値を操作することを示す型変数です。 これにより、クラスをさまざまな種類のデータに対して使用することが可能になり、コードの重複を削減し、コードの汎用性を高めることができます。
角度括弧の使い方
クラス名の後に角度括弧 (<>) を配置し、その中にジェネリック型パラメーターをカンマ区切りで列挙します。 例えば、次のコードは T
というジェネリック型パラメーターを持つ MyClass
というクラスを定義します。
class MyClass<T> {
// ...
}
ジェネリック型パラメーターは、さまざまな場面で使用できます。 以下は、いくつかの例です。
- 配列の型推論
ジェネリック型パラメーターを使用して、配列の要素の型を推論することができます。 例えば、次のコードは、T
型の要素を持つMyArray
というジェネリック型配列を定義します。
class MyArray<T> {
private items: T[];
constructor(items: T[]) {
this.items = items;
}
// ...
}
- 制約の指定
ジェネリック型パラメーターに制約を指定することで、その型が満たさなければならない条件を定義することができます。 例えば、次のコードは、T
型がnumber
型またはstring
型である必要があることを示します。
class MyFunction<T extends number | string> {
public process(value: T): T {
// ...
}
}
- 型変数の使用
ジェネリック型パラメーターは、クラス内のさまざまな場所で型変数として使用することができます。 例えば、次のコードは、T
型の値を格納するvalue
というプロパティを持つMyClass
というクラスを定義します。
class MyClass<T> {
private value: T;
constructor(value: T) {
this.value = value;
}
public getValue(): T {
return this.value;
}
}
Brackets との関係
Brackets は、テキストエディタや IDE のようなコード編集ツールです。 Brackets は、ジェネリック型パラメーターを含む TypeScript コードを編集するための機能を提供しています。 例えば、Brackets は、ジェネリック型パラメーターの自動補完や、ジェネリック型パラメーターの使用箇所をハイライトする機能を提供しています。
この例では、T
型の要素を持つ MyArray
というジェネリック型配列を定義します。
class MyArray<T> {
private items: T[];
constructor(items: T[]) {
this.items = items;
}
public length(): number {
return this.items.length;
}
public get(index: number): T {
return this.items[index];
}
public push(item: T): void {
this.items.push(item);
}
}
このコードを使用するには、次のようにインスタンスを作成し、要素を追加して取得することができます。
const numbersArray = new MyArray<number>([1, 2, 3, 4, 5]);
console.log(numbersArray.length()); // 5
console.log(numbersArray.get(2)); // 3
numbersArray.push(6);
console.log(numbersArray); // [1, 2, 3, 4, 5, 6]
この例では、T
型と U
型の引数を受け取り、T
型の値を返す MyFunction
というジェネリック型関数を定義します。
class MyFunction<T, U> {
public process(value: T, otherValue: U): T {
// ... value と otherValue を処理する ...
return value;
}
}
このコードを使用するには、次のように関数を呼び出すことができます。
const myFunction = new MyFunction<number, string>();
const result = myFunction.process(10, "Hello");
console.log(result); // 10
この例では、T
型が number
型または string
型である必要があることを示す MyClass
というクラスを定義します。
class MyClass<T extends number | string> {
private value: T;
constructor(value: T) {
this.value = value;
}
public getValue(): T {
return this.value;
}
}
const myClass1 = new MyClass(10);
console.log(myClass1.getValue()); // 10
const myClass2 = new MyClass("Hello");
console.log(myClass2.getValue()); // Hello
型推論
この例では、T
型を明示的に指定せずにジェネリック型を使用する方法を示します。
function swap<T>(x: T, y: T): [T, T] {
return [y, x];
}
const [a, b] = swap(10, "Hello");
console.log(a); // Hello
console.log(b); // 10
このコードでは、swap
関数の型パラメーター T
は明示的に指定されていませんが、関数の引数と返り値の型から推論されます。
注意事項
ジェネリック型パラメーターを使用する際には、以下の点に注意する必要があります。
- ジェネリック型パラメーターは、型安全性を確保するために慎重に使用することが重要です。 型制約を使用して、ジェネリック型パラメーターが満たさなければならない条件を定義することができます。
- ジェネリック型パラメーターは、クラスや関数の型パラメーターとしてのみ使用できます。 変数やプロパティの型としては使用できません。
TypeScriptにおけるジェネリック型パラメーターの使用例:追加解説
型安全なコレクション操作
ジェネリック型パラメーターは、コレクション操作の型安全性を確保するために非常に役立ちます。 例えば、次のコードは、T
型の要素を持つ MyCollection
というジェネリック型コレクションクラスを定義します。
class MyCollection<T> {
private items: T[] = [];
public add(item: T): void {
this.items.push(item);
}
public remove(item: T): boolean {
return this.items.splice(this.items.indexOf(item), 1).length > 0;
}
public contains(item: T): boolean {
return this.items.indexOf(item) !== -1;
}
public get(index: number): T | undefined {
return this.items[index];
}
public size(): number {
return this.items.length;
}
}
このクラスを使用すると、次のように安全な方法でコレクションを操作することができます。
const numbersCollection = new MyCollection<number>();
numbersCollection.add(1);
numbersCollection.add(2);
numbersCollection.add(3);
console.log(numbersCollection.contains(2)); // true
console.log(numbersCollection.get(1)); // 2
const stringsCollection = new MyCollection<string>();
stringsCollection.add("Hello");
stringsCollection.add("World");
console.log(stringsCollection.contains("World")); // true
console.log(stringsCollection.get(0)); // Hello
このコードでは、コンパイラは各コレクションの要素型を検証し、型エラーが発生する可能性のある不正な操作を検出します。
関数型プログラミングにおけるジェネリック型
ジェネリック型パラメーターは、関数型プログラミングの概念を TypeScript に取り入れるためにも使用できます。 例えば、次のコードは、map
関数、filter
関数、reduce
関数などの高階関数を実装する方法を示します。
function map<T, U>(collection: T[], transform: (item: T) => U): U[] {
const result: U[] = [];
for (const item of collection) {
result.push(transform(item));
}
return result;
}
function filter<T>(collection: T[], predicate: (item: T) => boolean): T[] {
const result: T[] = [];
for (const item of collection) {
if (predicate(item)) {
result.push(item);
}
}
return result;
}
function reduce<T, U>(collection: T[], initialValue: U, reducer: (accumulator: U, item: T) => U): U {
let accumulator = initialValue;
for (const item of collection) {
accumulator = reducer(accumulator, item);
}
return accumulator;
}
これらの高階関数は、ジェネリック型パラメーターを使用して、さまざまな種類のデータに対して汎用的に使用することができます。
型パラメーターの制約
ジェネリック型パラメーターに制約を指定することで、その型が満たさなければならない条件を定義することができます。 例えば、次のコードは、T
型が number
型である必要があることを示す MyMath
というクラスを定義します。
class MyMath<T extends number> {
public static sum(x: T, y: T): T {
return x + y;
}
public static difference(x: T, y: T): T {
return x - y;
}
}
const result1 = MyMath.sum(10, 20); // 30
const result2 = MyMath.difference(20, 10); // 10
typescript brackets