序章

動的で再利用可能なコードを作成する場合は、Do n’t-Repeat-Yourself( DRY )の原則に従うことが重要です。 ジェネリックスを使用すると、TypeScriptコードでこれを実現するのに役立ちます。

ジェネリックを使用すると、動的で再利用可能なジェネリックコードブロックを記述できます。 さらに、TypeScriptのジェネリックスをクラス、インターフェイス、および関数に適用できます。

この記事では、ジェネリックスをTypeScriptコードに統合し、それらを関数とクラスに適用します。 また、インターフェイスを使用してTypeScriptでジェネリックスに制約を追加する方法についても学習します。

前提条件

このチュートリアルを正常に完了するには、次のものが必要です。

  • マシンにインストールされているTypeScriptの最新バージョン。 この新しいTypeScriptプロジェクトを設定する方法チュートリアルは、これを達成するのに役立ちます。
  • 最新バージョンの ts-node インストールされています。 これは、TypeScriptコードをテストして実行する場合に必要です。 このTypeScriptスクリプトをts-nodeで簡単に実行するチュートリアルは、始めるのに最適な場所です。
  • TypeScriptでの関数とクラスの記述に精通していること。

ステップ1—ジェネリックを理解する

場合によっては、異なるデータ型に対して同じコードブロックを繰り返したいことがあります。 2つの異なるデータ型に使用されている同じ関数の例を次に示します。

// for number type
function fun(args: number): number {
  return args;
}

// for string type
function fun(args: string): string {
  return args;
}

この例では、同じ関数が次の場合に繰り返されていることに注意してください。 numberstring 種類。 ジェネリックは、上記の例のように同じコードブロックを記述して繰り返す代わりに、一般化されたメソッドを記述するのに役立ちます。

と呼ばれるタイプがあります any、これを使用して、コードのジェネリックスと同じ効果を実現できます。 を使用して any タイプを使用すると、タイプチェックをオプトアウトできます。 でも、 any ではありません type-safe. これは、 any あなたに例外を与えることができます。

これを実際に確認するには、 any 前のコード例に入力します。

function fun(args: any): any {
 return args;
}

スワッピング numberstring タイプに any typeは、関数をジェネリックにします。 しかし、落とし穴があります。 any タイプは、 fun 関数は任意のデータを受け入れることができます。 その結果、型安全性も失われます。

を使用していますが any typeは、TypeScriptコードをより一般的にする方法であり、常に最良のオプションであるとは限りません。 次のステップでは、タイプセーフなジェネリックを作成するための別のオプションを検討します。

ステップ2—タイプセーフジェネリックの作成

タイプセーフなジェネリックを作成するには、次を使用する必要があります Type パラメーター。 Type パラメータはによって定義されます T また <T>. これらは、クラス、インターフェイス、および関数に渡されるパラメーターのデータ型を示します。

に戻る fun 機能、使用 T ジェネリック関数をタイプセーフにするには:

index.ts
function fun<T>(args:T):T {
  return args;
}

結果として、 fun はタイプセーフなジェネリック関数になりました。 このタイプセーフなジェネリック関数をテストするには、次の名前の変数を作成します result に等しく設定します fun とともに string タイプパラメータ。 引数は Hello World ストリング:

index.ts
let result = fun<string>("Hello World");

を使用してみてください fun で機能する number タイプ。 引数を次のように設定します 200:

index.ts
let result2 = fun<number>(200);

このコードの結果を確認したい場合は、次のように含めることができます console.log 印刷するステートメント resultresult2 コンソールへ:

index.ts
console.log(result);
console.log(result2);

最終的に、コードは次のようになります。

index.ts
function fun<T>(args:T):T {
  return args;
}

let result = fun<string>("Hello World");
let result2 = fun<number>(200);

console.log(result);
console.log(result2);

使用する ts-node このTypeScriptコードをコンソールで実行するには:

  1. npx ts-node index.ts

コードはエラーなしでレンダリングされます。 次の出力が表示されます。

Output
Hello World 200

1つのパラメーターを持つ関数のタイプセーフなジェネリックを作成できるようになりました。 また、多くの異なるタイプの複数のパラメーターを持つ関数のジェネリックを作成する方法を知ることも重要です。

ステップ3—多くのタイプのパラメーターでジェネリックを使用する

関数に多くのパラメーターがある場合は、異なる文字を使用してタイプを示すことができます。 使用する必要はありません T:

params.ts
function fun<T, U, V>(args1:T, args2: U, args3: V): V {
  return args3;
}

この関数は3つのパラメーターを取ります。 args1, args2、 と arg3、および戻ります args3. これらのパラメータは特定のタイプに制限されていません。 それの訳は T, U、 と V のジェネリック型として使用されます fun 関数のパラメーター。

と呼ばれる変数を作成します result3 に割り当てます fun. を含める <string, number, boolean> 記入するタイプ T, U、 と V ジェネリック型。 引数には、括弧内に保持された文字列、数値、およびブール値を含めます。

params.ts
let result3 = fun<string, number, boolean>('hey', 3, false);

これにより、3番目の引数が返されます。 false. これを確認するには、 console.log 声明:

params.ts
console.log(result3);

を実行します ts-node あなたを見るコマンド console.log ステートメント出力:

  1. npx ts-node params.ts

これが出力になります:

Output
false

これで、複数のパラメーターを持つ関数の汎用型を作成できます。 関数と同様に、ジェネリックは classesinterfaces 同じように。

ステップ4—汎用クラスの作成

総称関数のように、クラスも総称にすることができます。 The type 角度のパラメータ(<>)関数と同様に、角かっこが使用されます。 そうして <T> typeは、メソッドとプロパティを定義するためにクラス全体で使用されます。

両方を取るクラスを作成する numberstring 入力し、それらの入力で配列を作成します。 使用する <T> ジェネリック型パラメーターとして:

classes.ts
class customArray<T> {
  private arr: T[] = [];
}

これで、さまざまなタイプのアイテムを取り込む配列が配置されました。 と呼ばれるメソッドを作成します getItems それは customArray 配列:

classes.ts
getItems (arr: T[]) {
  return this.arr = arr;
}

と呼ばれるメソッドを作成します addItem の最後に新しいアイテムを追加します customArray 配列:

classes.ts
addItem(item:T) {
  this.arr.push(item);
}

The arr: T[] 引数は、配列内の項目が任意のタイプであることを意味します。 そう customArray 数値、ブール値、または文字列の配列にすることができます。

と呼ばれるメソッドを追加します removeItem 指定されたアイテムをから削除します customArray:

classes.ts
removeItem(item: T) {
  let index = this.arr.indexOf(item);
    if(index > -1)
      this.arr.splice(index, 1);
}

以下のような addItem 方法、 removeItem 任意のタイプのパラメーターを受け取り、指定されたパラメーターをから削除します customArray 配列。

今ジェネリッククラス customArray 完了です。 のインスタンスを作成します customArray 為に numberstring 種類。

と呼ばれる変数を宣言します numObj のインスタンスに等しいセット customArray 為に number 種類:

classes.ts
let numObj = new customArray<number>();

使用 addItem 番号を追加する方法 10numObj:

classes.ts
numObj.addItem(10);

以来 customArray は汎用であり、文字列の配列を作成するためにも使用できます。 と呼ばれる変数を作成します strObj のインスタンスに等しいセット customArray 文字列タイプの場合:

classes.ts
let strObj = new customArray<string>();

使用 addItem 文字列を追加するメソッド RobinstrObj 配列。

classes.ts
strObj.addItem(“Robin”);

コードの結果を確認するには、 console.log 両方のステートメント numObjstrObj:

classes.ts
console.log(numObj);
console.log(strObj);

最終的に、コードは次のようになります。

classes.ts
class customArray<T> {
  private arr: T[] = [];

  getItems(arr: T[]) {
    return this.arr = arr;
  }

  addItem(item:T) {
    this.arr.push(item);
  }

  removeItem(item: T) {
    let index = this.arr.indexOf(item);
      if(index > -1)
        this.arr.splice(index, 1);
  }
}

let numObj = new customArray<number>();
numObj.addItem(10);

let strObj = new customArray<string>();
strObj.addItem(“Robin”);

console.log(numObj);
console.log(strObj);

走った後 ts-node、これはあなたが受け取る出力です:

Output
customArray { arr: [ 10 ] } customArray { arr: [ 'Robin' ] }

あなたは customArray 両方のクラス numberstring 種類。 ジェネリック型を使用することでこれを達成することができました。 ただし、ジェネリックスの使用にはいくつかの制約があります。 これについては、次のステップで説明します。

ステップ5—一般的な制約を理解する

これまで、ジェネリックスを使用して関数とクラスを作成してきました。 ただし、ジェネリックを使用することには欠点があります。 この欠点を実際に確認するには、次の関数を記述します。 getLength それは length 関数の引数の:

制約.ts
function getLength<T>(args: T) : number {
  return args.length;
}

この関数は、通過するタイプに length プロパティですが、 length プロパティは例外をスローします。

この問題には、一般的な制約を作成するという解決策があります。 これを行うには、最初にと呼ばれるインターフェースを作成する必要があります funcArgs と定義します length 財産:

制約.ts
interface funcArgs {
  length: number;
}

今、変更します getLength 機能と extend それを含めるには funcArgs 制約としてのインターフェース:

制約.ts
function getLength<T extends funcArgs>(args:T) : number {
  return args.length;
}

インターフェイスを使用して一般的な制約を作成しました。 さらに、あなたも拡張しました getLength このインターフェースで機能します。 今必要です length 必須パラメータとして。 これにアクセスする getLength 長さパラメーターを持たない引数を持つ関数は、例外メッセージを表示します。

これが実際に動作していることを確認するには、次の変数を宣言します。 result4 に割り当てます getLength3 その議論として:

制約.ts
let result4 = getLength(3);

の値が length パラメータは含まれていません:

Output
⨯ Unable to compile TypeScript: index.ts:53:25 - error TS2345: Argument of type 'number' is not assignable to parameter of type 'funcArgs'. 53 let result4 = getLength(3);

を呼び出すには getLength 関数、あなたは含める必要があります length と一緒に引数 name 口論:

制約.ts
let result = getLength({ length: 5, name: 'Hello'});

これは、関数を呼び出す正しい方法です。 この通話には length プロパティ、およびあなたの関数はうまく機能します。 エラーメッセージは表示されません。

結論

このチュートリアルでは、ジェネリックスをTypeScript関数とクラスに正常に統合しました。 ジェネリックの制約も含めました。

次のステップとして、ReactでTypeScriptを使用する方法を学ぶことに興味があるかもしれません。 VS CodeでTypeScriptを操作する方法を学びたい場合は、この VisualStudioCodeでTypeScriptを操作する方法の記事から始めるのが最適です。