TypeScriptジェネリックの使用

TypeScriptジェネリックの使用

序文:

JavaScriptは弱い型付けの言語であるため、 API をカプセル化するとさまざまな用途に使用できますが、弱い型付けによって得られる最終結果は、私たちが望むものではありません。

TypeScript の登場によりこの問題は解決しましたが、API の再利用を考えると、TypeScript はそれほど柔軟ではないようです。このとき、 any 型を使用すると柔軟性のなさという問題を解決できますが、JavaScript の問題に戻り、最終結果が期待どおりにならない可能性があります。

この問題を解決するために、 TypeScriptジェネリックの概念を導入しました。ジェネリックを使用すると、関数、インターフェース、またはクラスを定義するときに特定の型を事前に指定する必要がなくなり、代わりに使用時に型を指定できます。その目的は、コードをより広範囲に再利用することです。

1. 使いやすい

ここで、主に同じ型の 2 つの値を受け入れ、2 つのパラメーターの連結された値を返すjoin関数を定義する必要があります。サンプルコードは次のとおりです。

// いわゆるジェネリックは、より一般的な意味では、一般的に参照される型です。 // 同じ型の 2 つのパラメーターを受け入れ、連結された値を返す join 関数を定義します。
関数 join<T>(最初: T、2番目: T) {
  `${first}${second}` を返す
}
// ここで、T は文字列として指定されます typejoin<string>('第一', '第二') //第一第二// ここでは、型推論を通じて、コンパイラは渡されたパラメータに基づいて型を自動的に推論しますjoin(1, 2) // 12

ジェネリックは山括弧 <> を使用して定義されます。結合関数を定義するときに、どの型が受け入れられるかはわかりませんが、2 つの型が同じでなければならないことは確かです。このような要件を満たしたい場合、ジェネリックなしで解決するのはそれほど簡単ではありません。

関数を呼び出す場合、2 つの方法があります。1 つは型を文字列型として直接指定する方法、もう 1 つは型推論を使用する方法です。エディターは渡されたパラメーターに基づいて型を自動的に決定するのに役立ちます。

2. 関数内でジェネリックを使用する

関数を定義するときに、複数のジェネリックを使用することができ、数量と使用方法が対応している限り、戻り値の型もジェネリックを通じて指定できます。

サンプルコードは次のとおりです

関数の恒等式<T, Y, P>(1番目: T、2番目: Y、3番目: P): Y {
  2番目を返す
}
//指定された型 identity<boolean, string, number>(true, 'string', 123) // string // 型推論 identity('string', 123, true) // true

3. クラス内でジェネリックを使用する

ジェネリックは関数だけでなくクラスでも使用できます。

サンプルコードは次のとおりです。

クラスDataManager<T> {
  // T 型のプライベート配列を持つクラスを定義します。constructor(private data: T[]) {}
  // インデックスに基づいて配列内の値を取得します getItem(index: number): T {
    this.data[インデックス]を返す
  }
}
const data = new DataManager(['一碗周'])
data.getItem(0) // 周の一杯

さらに、ジェネリックはインターフェースから継承することもできます。サンプルコードは次のとおりです。

インターフェースアイテム{
  名前: 文字列
}
クラス DataManager<T extends Item> {
  // T 型のプライベート配列を持つクラスを定義します。constructor(private data: T[]) {}
  // インデックスに基づいて配列内の値を取得します getItem(index: number): string {
    this.data[index].nameを返す
  }
}
const data = new DataManager([{ name: '一碗周' }])
data.getItem(0) // 周の一杯

ジェネリック制約の効果を得るには、 extends使用します。上記のコードでは、渡された値が name 属性を持つように制約する必要があります。そうでない場合は、例外がスローされます。

4. ジェネリック制約における型パラメータの使用

次のような要件があるとします。いくつかのプロパティを含むプライベート オブジェクトを持つクラスを定義し、キーを通じて対応する値を取得するメソッドを定義します。

実装コードは次のとおりです。

// インターフェースを定義する interface Person {
  名前: 文字列
  年齢: 番号
  趣味: 弦楽器
}
// クラスを定義する class Me {
  コンストラクター(プライベート情報: Person) {}
  getInfo(キー: 文字列) {
    this.info[キー]を返す
  }
}
const me = 新しい Me({
  名前:「周の一杯」
  年齢: 18歳
  趣味:「コーディング」
})
// me.getInfo() を呼び出すと、未定義の値が返される可能性があります。たとえば、me.getInfo('myName') // undefined

上記のコードでは、インスタンス オブジェクトでgetInfo()メソッドを呼び出して、存在しないプロパティを渡すと、undefined が返されます。 undefined返すメソッドを呼び出すのはTypeScriptのスタイルではありません。

この問題は、特定の型のすべてのキーを取得するために使用できる keyof 演算子によって解決できます。その戻り値の型はユニオン型です。

サンプルコードは次のとおりです。

type myPerson = keyof Person // '名前' | '年齢' | '趣味'

これで、この演算子を使用して上記の問題を解決できます。

サンプルコードは次のとおりです。

クラスMe{
  コンストラクター(プライベート情報: Person) {}
  // これは getInfo<T extends keyof Person>(key: T): Person[T] { と同じです。
    this.info[キー]を返す
  }
  // getInfo<T extends 'name' | 'age' | 'hobby'>(key: T): Person[T] {
  // this.info[key]を返す
  // }
}
const me = 新しい Me({
  名前:「周の一杯」
  年齢: 18歳
  趣味:「コーディング」
})
// 不明なプロパティが渡された場合、me.getInfo() を呼び出すとコンパイル エラーが発生します。me.getInfo('myName') // エラー: '"myName"' 型の引数は、'keyof Person' 型のパラメーターに割り当てることはできません。

オブジェクトに存在しないプロパティにアクセスすると、コンパイルが異常になります。

TypeScript ジェネリックの使用に関するこの記事はこれで終わりです。TypeScript ジェネリックに関するその他の関連コンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • TypeScript ジェネリックを簡単に説明する方法
  • TypeScript ジェネリックパラメータのデフォルト型と新しい厳密なコンパイルオプション
  • フロントエンドにおけるTypescriptの一般的な概念の深い理解
  • TypeScript のジェネリック使用法とジェネリックインターフェースの組み合わせ

<<:  MySQL における datetime と timestamp の違いと選択

>>:  CSSを使用してすべての子要素を選択する方法の詳細な説明

推薦する

CentOS のファイルと権限の基本操作チュートリアル

序文始める前に、ファイル属性とファイル属性を変更する方法について簡単に理解しておく必要があります。 ...

Vueはシンプルなメモ帳機能を実装します

この記事では、参考までに、簡単なメモ帳機能を実装するためのVueの具体的なコードを紹介します。具体的...

Vue ルーターにパラメータを渡すときにページを更新するとパラメータが失われる問題に対処する方法

目次概要方法1: params経由でパラメータを渡す方法2: クエリを通じてパラメータを渡す方法3:...

JS と Nodejs におけるイベント駆動型開発についての簡単な説明

目次イベント駆動型とパブリッシュ・サブスクライブ型ブラウザの JavaScript ではイベント駆動...

CentOS 7.6 への MySQL 5.7 GA バージョンのインストール チュートリアル図

目次環境の準備環境の準備mariadbをアンインストールする rpm -qa | grep mari...

Dockerにおけるコンテナとイメージの違いについてお話ししましょう

鏡とは何ですか?イメージは、複数のイメージ レイヤー (UnionFS および AUFS ファイル ...

Reactのコンテキストとプロパティの説明

目次1. 文脈1. 使用シナリオ2. 使用手順3. 結論2. 小道具の詳細1. 子供の財産2. 小道...

jQuery はテーブルのページング効果を実装します

この記事では、テーブルのページング効果を実現するためのjQueryの具体的なコードを参考までに紹介し...

MySql キャッシュ クエリの原理とキャッシュ監視およびインデックス監視の概要

クエリキャッシュ1. クエリキャッシュの動作原理クエリ ステートメントを実行する前に、MySQL は...

MySQLのサブクエリユニオンの効率性についての簡単な説明と

最近の製品テストでは、同時呼び出し数が 10 未満の場合に応答時間が 100 ミリ秒以内に維持できな...

Nginx 構成 PC サイトとモバイル サイトの分離によるリダイレクトの実現

PCサイトとモバイルサイトの分離設定にはnginxを使います。私のPCサイトとモバイルサイトは、SE...

MySQL での Truncate の使用法の詳細な説明

序文:テーブルをクリアしたいときは、truncate ステートメントをよく使用します。ほとんどの場合...

MySQL のストレージ エンジンの違いと比較

MyISAM ストレージエンジンMyISAM は ISAM ストレージ エンジンに基づいており、それ...

Windows での MySQL 8.0.12 のインストール手順と基本的な使用方法のチュートリアル

この記事では、WindowsでのMySQL 8.0.12のインストール手順と使用方法のチュートリアル...

Docker Alpine イメージのタイムゾーン問題に対する完璧な解決策

最近、Docker を使用して Java アプリケーションをデプロイしていたときに、タイムゾーンが間...