TypeScript ジェネリックを簡単に説明する方法

TypeScript ジェネリックを簡単に説明する方法

概要

TypeScript では、ジェネリックを使用して関連する関数の型を制限します。ここでの関数にはクラスのコンストラクターも含まれるため、クラスの宣言部分でもジェネリックを使用できます。では、ジェネリック医薬品とは一体何でしょうか?ジェネリックをシンプルに理解したらどうなるでしょうか?

ジェネリック医薬品とは

ジェネリックとは、関数、インターフェース、またはクラスを定義するときに特定の型を事前に指定せず、使用時に型を指定する機能を指します。

簡単に言えば、ジェネリックは型システムにおける「パラメータ」であり、その主な機能は型を再利用することです。上記の定義からわかるように、関数、インターフェース、クラスでのみ使用されます。これは js プログラム内の関数パラメータとは異なります (意味は同じですが)。Typescript は静的型システムであり、js がコンパイルされるときに型チェックを実行するシステムであるためです。そのため、ジェネリック パラメータは実際にはコンパイル プロセスの実行時に使用されます。関数パラメータとまったく同じ特性を持つため、「パラメータ」と呼ばれます。

関数increse(パラメータ) {
  // ...
}

型システムでは、ジェネリックを次のように使用します。

関数増加<T>(パラメータ: T): T {
  //...
}

param が型の場合、T はこの型に割り当てられ、戻り値では、型チェックのために T はこの型になります。

ビルドシステム

Typescript の型システム自体もプログラミングが必要であることはご存知でしょうが、そのプログラミング方法は奇妙です。プログラム コードに js コードを散りばめる必要があります (ts コードに js コードを散りばめるという言い方は奇妙です。なぜなら、直感的には ts コードが js コードに混ざっていると感じられるからです)。

プログラミングにおいて、最も重要な形式の 1 つは関数です。 Typescript の型プログラミングで、関数を見たことがありますか?いいえ。これは、ジェネリックがあるところには関数がありますが、関数の形式は js コードによって分割されるためです。最終製品を取得するには、Typescript をコンパイルする必要があります。コンパイルプロセス中に行うべきことは 2 つあります。1 つは、メモリ内で型プログラミング コードを実行して、型チェック システムを形成することです。つまり、js コードの型チェックを行うことができます。まず、typescript コンパイラは、ts プログラミング コードを実行した後、ランタイム チェック システムを取得します。この記事は Fei Zige のポッドキャストからのもので、このシステムを実行して、そこに散在する js コードに対して型アサーションを実行します。2 つ目は、js を出力することです。出力プロセス中、コンパイル システムは型プログラミング コードを実行しました。php コードで echo js コードを実行するのと同じように、php コードが実行され、表示されるのは js コードです。

この観点から TypeScript を見ると、なぜそれが JavaScript のスーパーセットと呼ばれ、コンパイルされた結果が JS になるのかをよりよく理解できるかもしれません。

ジェネリック医薬品の一般的な理解

TS コンパイル システムのロジックを理解したので、型プログラミングと JS 自体のビジネス プログラミングを感情的に区別できるようになりました。ここで言及している「ジェネリック」は、ts のコンパイルされたランタイム コードである型プログラミング部分にのみ存在します。

簡単な例を見てみましょう:

関数増加<T>(パラメータ: T): T {
  //...
}

このコードから js コードを分離し、型の説明テキストを使用してそれを表すとどうなるでしょうか?

//関数@typeを宣言し、パラメータはT、戻り値は(T): T 
@type = T => (T): T

// 関数を実行して、型 (number): number の型 F を取得します。
@F = @type(数値)

// 増加関数は F 型に準拠する必要があります。つまり、パラメータは数値で、戻り値も数値です。 
@@F
関数増加(パラメータ) { 
  // ... 
} 
@@終わり

実際には @@F のような構文はありません。型システムを別の観点から見ることができるように作成しました。

ジェネリックが一種の「パラメーター」であると理解したら、型システムの機能はどこにあるかという疑問が湧くかもしれません。 js 関数の場合は関数宣言文とパラメータを簡単に指摘できますが、ts ではこの部分は隠されています。ただし、特定の構造では型関数の影が簡単に確認できます。

// ジェネリックインターフェースを宣言します。これは関数を宣言するのと同じように記述します。記述には記述言語を使用します。@type = T => (T): T
インターフェース GenericIdentityFn<T> {
    (引数: T): T;
}

// この書き方はクロージャ関数に少し似ています。関数を宣言すると、すぐに実行されます。記述言語: @@[T => (T): T](any)
関数アイデンティティ<T>(引数: T): T {
    引数を返します。
}

// ジェネリックインターフェースの使用は関数の呼び出しに似ています。記述言語を使用して@type(number)を記述します。
myIdentity: GenericIdentityFn<number> = identity; とします。

上記のコード全体を説明テキストを使用して書き直してみましょう。

@GenericIdentityFn = T => (T): T

@@[T => (T): T](任意)
関数識別(引数) {
  戻り引数
}
@@終わり

@@GenericIdentityFn(数値)
myIdentity = identityとする
@@終わり

型システムで、@GenericIdentityFn と @some (匿名関数 @[T => (T): T]) の 2 つの関数を宣言します。これらは 2 つの関数ですが、実際にはまったく同じです。これは、TypeScript が構造型であるためです。つまり、型をチェックするときに、型変数自体のポインターを同じに保つ必要はなく、構造内の各ノードの型が同じかどうかのみを判別します。 @GenericIdentityFn と @some は、それぞれ identify と myIdentify を変更するために呼び出されます。呼び出し時に異なるパラメータを受け取るため、最終的な型チェック ルールが異なります。Identify では、パラメータと戻り値の型が同じであることだけを確認する必要があります。具体的な型については、any が使用されます。 myIdentify では、パラメータの戻り値の型が同じであることを確認するだけでなく、型が数値であることも要求します。

ジェネリッククラス

ジェネリック インターフェイスに加えて、クラス クラスもジェネリック化できます。つまり、「ジェネリック クラス」です。ジェネリック クラスの助けを借りて、ジェネリックを宣言して使用する手順を調べてみましょう。

クラス GenericNumber<T> {
    ゼロ値: T;
    追加: (x: T, y: T) => T;
}

myGenericNumber = new GenericNumber<number>() とします。

前回の記事のジェネリックインターフェースは関数の型を制約するためだけに使用されているため、関数のように記述されています。実際には、ジェネリックインターフェースとジェネリッククラスは記述言語を使用して再記述できます。上記の赤い部分を説明するために、説明的な言語を使用します。

@GenericNumber = T => クラス {
  ゼロ値: T;
  追加: (x: T, y: T) => T;
}

@GenericNumber 関数は T をパラメータとして受け取り、クラスを返します。パラメータ T は @type 関数本体で複数回使用されます。

@GenericIdentityFn = T => インターフェース { 
  (引数: T): T; 
}

以前のインターフェース GenericIdentityFn を再記述して、インターフェースに他のメソッドを追加できるようにします。

Array などの TypeScript の組み込み基本型がジェネリック インターフェイスおよびジェネリック クラスとして宣言された後でも、これらのインターフェイスおよびクラスは、使用時に <> を介してパラメータを渡す必要があることがわかります。本質的には、これらはすべて関数であるため、戻り値が異なるだけです。

ジェネリックの使用に関するその他の一般的な説明

次に複合型を記述する必要があります。

クラス動物{
    numLegs: 数値;
}

関数createInstance<A extends Animal>(c: new () => A): A {
    新しいc()を返します。
}

今は new() の部分を見るのではなく、山括弧内の extends 構文を見てみましょう。どのように理解すればよいでしょうか?実際、私たちが直面する疑問は、コンパイル時に、<A extends Animal> の山括弧内のコンテンツがいつ実行されるのか、それらの前かその間かということです。

// @type = (A extends Animal) => (new() => A): A
@type(T)
// それでも @type = A => (new() => A): A
@type(T は Animal を拡張します)

TypeScript は静的型システムであり、Animal は不変クラスであるため、山括弧の内容はクラスが作成される前に実行されていると推測できます。

@type = (A は Animal を拡張します) => (new() => A): A

つまり、@type(T) を使用して型を生成するには、まず T が Animal の構造を満たしている必要があり、その後、必要な型を取得できます。T が Animal クラスの構造を満たさなくなった場合、コンパイラは直接エラーを報告します。このエラーは、型チェックの段階ではなく、型システムの作成段階、つまり ts コードの実行段階で発生します。この状況は「一般的な制約」と呼ばれます。

さらに、<A,B> のような構文は、実際には関数パラメータと同じです。

@type = (A, B) => (A|B): 何らかの型

tsの組み込み基本型を見てみましょう: Array<number>

@配列 = 任意 => 任意[]

結論

Typescript のジェネリックは、実際には型生成関数のパラメーターです。この記事の内容はすべて架空のものであり、tsを理解する際にアイデアを展開するのにのみ適しています。実際のプログラミングには適していません。これをここに宣言します。

以上がTypeScriptジェネリックの詳しい説明です。TypeScriptジェネリックの詳細については、123WORDPRESS.COMの他の関連記事もご覧ください。

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

<<:  LinuxでのMySQLのインストール手順

>>:  spring-boot と docker-java に基づいて Docker コンテナの動的な管理と監視を実装します [完全なソース コードのダウンロード付き]

推薦する

vue3.0 でカルーセル コンポーネントをカプセル化する手順

目次1: カプセル化の考え方2. 包装工程3: ドットインジケーター4: 左と右のインジケーター5:...

SELinux 入門

カーネル 2.6 の時代には、アクセス制御セキュリティ ポリシーのメカニズムを提供するために新しいセ...

HTML_PowerNode Java アカデミーでテーブルを動的に追加する

さっそく、コードを直接投稿します。具体的なコードは次のとおりです。 <html> <...

デカルト積原理を使用してMySQLで複数のテーブルをクエリする方法を簡単に説明します。

MySQL マルチテーブルクエリ (直積原理)まず、データが使用するテーブルを決定します。デカルト...

HTML テーブルタグチュートリアル (3): 幅と高さの属性 WIDTH、HEIGHT

デフォルトでは、テーブルの幅と高さはコンテンツに応じて自動的に調整されます。テーブルの幅と高さを手動...

Vueリストデータを削除した後、ページを自動的に更新する方法と更新方法の詳細な説明

問題の説明:フロントエンドがデータの一部を削除したり、新しいデータを追加したりすると、バックエンドの...

Linux 継続的インテグレーションで Maven を自動的にインストールする方法

Mavenパッケージを解凍する tar xf apache-maven-3.5.4-bin.tar....

Vueはシンプルなデータ双方向バインディングを実装します

この記事では、Vueの具体的なコード例を参考までに紹介します。具体的な内容は以下のとおりです。初心者...

Linux クラウド サーバーに JDK と Tomcat をインストールするための詳細な手順 (推奨)

JDKをダウンロードしてインストールするステップ 1: まず、公式 Web サイト http://...

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

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

HTMLファイルとは何ですか?HTMLファイルを開く方法

HTML は Hypertext Markup Language の略です。現在、ほとんどの Web...

MySQL サービスを完全に削除する方法 (レジストリをクリーンアップする)

序文あるプロジェクトの実行可能ファイルをインストールすると、MySQL 自体をインストールできるよう...

nginx で複数の仮想ホストを設定する方法の例

nginx で仮想ホスト vhost を設定すると非常に便利です。 nginx設定ファイルnginx...

階段を転がす特殊効果を実現する JavaScript (jQuery 実装)

皆さんもJDを使ったことがあると思います。ホームページには非常によく見られる機能があります。階段の特...

MySQL の int、char、varchar のパフォーマンスを比較する

インターネットには、真実のように見える「噂」がたくさんあります。もちろん、悪意のあるものではありませ...