TypeScriptでジェネリックスを使用する方法
序章
動的で再利用可能なコードを作成する場合は、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;
}
この例では、同じ関数が次の場合に繰り返されていることに注意してください。 number
と string
種類。 ジェネリックは、上記の例のように同じコードブロックを記述して繰り返す代わりに、一般化されたメソッドを記述するのに役立ちます。
と呼ばれるタイプがあります any
、これを使用して、コードのジェネリックスと同じ効果を実現できます。 を使用して any
タイプを使用すると、タイプチェックをオプトアウトできます。 でも、 any
ではありません type-safe
. これは、 any
あなたに例外を与えることができます。
これを実際に確認するには、 any
前のコード例に入力します。
function fun(args: any): any {
return args;
}
スワッピング number
と string
タイプに any
typeは、関数をジェネリックにします。 しかし、落とし穴があります。 any
タイプは、 fun
関数は任意のデータを受け入れることができます。 その結果、型安全性も失われます。
を使用していますが any
typeは、TypeScriptコードをより一般的にする方法であり、常に最良のオプションであるとは限りません。 次のステップでは、タイプセーフなジェネリックを作成するための別のオプションを検討します。
ステップ2—タイプセーフジェネリックの作成
タイプセーフなジェネリックを作成するには、次を使用する必要があります Type
パラメーター。 Type
パラメータはによって定義されます T
また <T>
. これらは、クラス、インターフェイス、および関数に渡されるパラメーターのデータ型を示します。
に戻る fun
機能、使用 T
ジェネリック関数をタイプセーフにするには:
function fun<T>(args:T):T {
return args;
}
結果として、 fun
はタイプセーフなジェネリック関数になりました。 このタイプセーフなジェネリック関数をテストするには、次の名前の変数を作成します result
に等しく設定します fun
とともに string
タイプパラメータ。 引数は Hello World
ストリング:
let result = fun<string>("Hello World");
を使用してみてください fun
で機能する number
タイプ。 引数を次のように設定します 200
:
let result2 = fun<number>(200);
このコードの結果を確認したい場合は、次のように含めることができます console.log
印刷するステートメント result
と result2
コンソールへ:
console.log(result);
console.log(result2);
最終的に、コードは次のようになります。
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コードをコンソールで実行するには:
- npx ts-node index.ts
コードはエラーなしでレンダリングされます。 次の出力が表示されます。
OutputHello World
200
1つのパラメーターを持つ関数のタイプセーフなジェネリックを作成できるようになりました。 また、多くの異なるタイプの複数のパラメーターを持つ関数のジェネリックを作成する方法を知ることも重要です。
ステップ3—多くのタイプのパラメーターでジェネリックを使用する
関数に多くのパラメーターがある場合は、異なる文字を使用してタイプを示すことができます。 使用する必要はありません T
:
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
ジェネリック型。 引数には、括弧内に保持された文字列、数値、およびブール値を含めます。
let result3 = fun<string, number, boolean>('hey', 3, false);
これにより、3番目の引数が返されます。 false
. これを確認するには、 console.log
声明:
console.log(result3);
を実行します ts-node
あなたを見るコマンド console.log
ステートメント出力:
- npx ts-node params.ts
これが出力になります:
Outputfalse
これで、複数のパラメーターを持つ関数の汎用型を作成できます。 関数と同様に、ジェネリックは classes
と interfaces
同じように。
ステップ4—汎用クラスの作成
総称関数のように、クラスも総称にすることができます。 The type
角度のパラメータ(<>
)関数と同様に、角かっこが使用されます。 そうして <T>
typeは、メソッドとプロパティを定義するためにクラス全体で使用されます。
両方を取るクラスを作成する number
と string
入力し、それらの入力で配列を作成します。 使用する <T>
ジェネリック型パラメーターとして:
class customArray<T> {
private arr: T[] = [];
}
これで、さまざまなタイプのアイテムを取り込む配列が配置されました。 と呼ばれるメソッドを作成します getItems
それは customArray
配列:
getItems (arr: T[]) {
return this.arr = arr;
}
と呼ばれるメソッドを作成します addItem
の最後に新しいアイテムを追加します customArray
配列:
addItem(item:T) {
this.arr.push(item);
}
The arr: T[]
引数は、配列内の項目が任意のタイプであることを意味します。 そう customArray
数値、ブール値、または文字列の配列にすることができます。
と呼ばれるメソッドを追加します removeItem
指定されたアイテムをから削除します customArray
:
removeItem(item: T) {
let index = this.arr.indexOf(item);
if(index > -1)
this.arr.splice(index, 1);
}
以下のような addItem
方法、 removeItem
任意のタイプのパラメーターを受け取り、指定されたパラメーターをから削除します customArray
配列。
今ジェネリッククラス customArray
完了です。 のインスタンスを作成します customArray
為に number
と string
種類。
と呼ばれる変数を宣言します numObj
のインスタンスに等しいセット customArray
為に number
種類:
let numObj = new customArray<number>();
使用 addItem
番号を追加する方法 10
に numObj
:
numObj.addItem(10);
以来 customArray
は汎用であり、文字列の配列を作成するためにも使用できます。 と呼ばれる変数を作成します strObj
のインスタンスに等しいセット customArray
文字列タイプの場合:
let strObj = new customArray<string>();
使用 addItem
文字列を追加するメソッド Robin
に strObj
配列。
strObj.addItem(“Robin”);
コードの結果を確認するには、 console.log
両方のステートメント numObj
と strObj
:
console.log(numObj);
console.log(strObj);
最終的に、コードは次のようになります。
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
、これはあなたが受け取る出力です:
OutputcustomArray { arr: [ 10 ] }
customArray { arr: [ 'Robin' ] }
あなたは customArray
両方のクラス number
と string
種類。 ジェネリック型を使用することでこれを達成することができました。 ただし、ジェネリックスの使用にはいくつかの制約があります。 これについては、次のステップで説明します。
ステップ5—一般的な制約を理解する
これまで、ジェネリックスを使用して関数とクラスを作成してきました。 ただし、ジェネリックを使用することには欠点があります。 この欠点を実際に確認するには、次の関数を記述します。 getLength
それは length
関数の引数の:
function getLength<T>(args: T) : number {
return args.length;
}
この関数は、通過するタイプに length
プロパティですが、 length
プロパティは例外をスローします。
この問題には、一般的な制約を作成するという解決策があります。 これを行うには、最初にと呼ばれるインターフェースを作成する必要があります funcArgs
と定義します length
財産:
interface funcArgs {
length: number;
}
今、変更します getLength
機能と extend
それを含めるには funcArgs
制約としてのインターフェース:
function getLength<T extends funcArgs>(args:T) : number {
return args.length;
}
インターフェイスを使用して一般的な制約を作成しました。 さらに、あなたも拡張しました getLength
このインターフェースで機能します。 今必要です length
必須パラメータとして。 これにアクセスする getLength
長さパラメーターを持たない引数を持つ関数は、例外メッセージを表示します。
これが実際に動作していることを確認するには、次の変数を宣言します。 result4
に割り当てます getLength
と 3
その議論として:
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
口論:
let result = getLength({ length: 5, name: 'Hello'});
これは、関数を呼び出す正しい方法です。 この通話には length
プロパティ、およびあなたの関数はうまく機能します。 エラーメッセージは表示されません。
結論
このチュートリアルでは、ジェネリックスをTypeScript関数とクラスに正常に統合しました。 ジェネリックの制約も含めました。
次のステップとして、ReactでTypeScriptを使用する方法を学ぶことに興味があるかもしれません。 VS CodeでTypeScriptを操作する方法を学びたい場合は、この VisualStudioCodeでTypeScriptを操作する方法の記事から始めるのが最適です。