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 コンテナの動的な管理と監視を実装します [完全なソース コードのダウンロード付き]

推薦する

nginx プロキシ サーバーで双方向証明書検証を構成する方法

証明書チェーンを生成するスクリプトを使用して、ルート証明書、中間証明書、および 3 つのクライアント...

CSS の一部のプロパティの前には「*」または「_」が付きます。

CSS の一部のプロパティの前には「*」または「_」が付きます。さまざまなブラウザを識別する例えば...

Docker コンテナに TensorRT をインストールする際の問題

Ubuntu にインストールされているバージョンをアンインストールします。 sudo apt-get...

Nginx リバース プロキシから go-fastdfs へのケースの説明

背景go-fastdfs は、http プロトコルをサポートする分散ファイルシステムです。一般的なプ...

XHTML 2.0 新機能プレビュー

<br />ブラウザが次世代のXHTMLを処理できるようになる前に、このよりリッチなコン...

モバイル署名機能を実装するJavaScript

この記事では、モバイル署名機能を実装するためのJavaScriptの具体的なコードを参考までに共有し...

Vue における Vue.use() の原理と基本的な使用法

目次序文1. 例で理解する2. ソースコードを分析する3. まとめ要約する序文他の人のコンポーネント...

MySQL の列から行への変換、フィールドの結合方法 (必読)

データシート:列から行へ: max(case when then) を使用max---集計関数は最大...

MySQLはinit-connectを使用してアクセス監査機能の実装を増やします

まず init-connect を通じて mysql 接続を初期化し、次にインスタンスに接続する必要...

数千万のデータを扱うMySQLのページングクエリのパフォーマンスを最適化する

MySQL のデータ量が多い場合、制限ページングが使用されます。ページ数が増えると、クエリの効率が低...

XHTML 入門チュートリアル: テーブルタグの応用

<br />テーブルは XHTML では扱いにくいタグなので、このセクションで理解するだ...

RedHat 6.5 に MySQL 5.7 をインストールするための詳細なチュートリアル

RedHat6.5インストールMySQL5.7チュートリアル共有、参考までに、具体的な内容は次のとお...

ウェブページ作成のヒントのまとめ

序文この記事は主に、日常の Web ページ制作で遭遇する問題解決スキルの一部をまとめ、皆さんの参考と...

MySQL における識別子の大文字と小文字の区別の問題の詳細な分析

MySQL では、テーブル名の大文字と小文字の区別の問題が発生する可能性があります。実際、これはプラ...

HTML フォーム タグの使用方法を学ぶチュートリアル

HTML のフォームを使用して、ユーザーからさまざまな種類の入力情報を収集できます。フォームは、実際...