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

推薦する

MySQL 5.7.18 のインストールと設定方法のグラフィックチュートリアル (CentOS7)

LinuxにMySQL 5.7.18をインストールする方法1. MySQLをダウンロードします。公...

Linuxでのcrontabの使い方と注意点の詳しい説明

Crontab は定期的な実行を設定するために使用されるコマンドです。そのデーモン プロセスは cr...

Vue3とTypeScriptを組み合わせたプロジェクト開発の実践の概要

目次概要1. コンポジションAPI 1. ref と reactive の違いは何ですか? 2. 周...

tomcat9.exeをクリックするとクラッシュする問題を解決する方法

ある読者から連絡があり、ダウンロードが終了し、操作がまだ開始されていないのに、なぜ Tomcat の...

LinuxにKafkaをインストールする

目次1.1 前提条件としてのJava環境1.2 Zookeeperのインストールと設定1.3 Kaf...

追加、削除、変更、クエリを実行するための JS 操作オブジェクト配列のサンプルコード

1. はじめに最近、私は友人が JSON 配列を追加、削除、変更するための簡単なページを作成するのを...

Linux で Xfce デスクトップ環境を使用すべき 8 つの理由

いくつかの理由(好奇心も含む)から、数週間前に Linux デスクトップとして Xfce を使い始め...

Vue3は画像拡大鏡効果を実現します

この記事の例では、画像拡大鏡効果を実現するためのVue3の具体的なコードを参考までに共有しています。...

mysql バックアップ スクリプト mysqldump の使い方の詳細な説明

この記事では、参考までにMySQLバックアップスクリプトを紹介します。具体的な内容は次のとおりです。...

動的な色切り替えの実装コードをサポートするために、CSS で SVG 画像を参照します。

表示する svg 画像を追加すると、React はファイルが見つからないというメッセージを表示します...

HTML 中国語文字エンコード標準の概要

HTML では、Web ページで使用されるエンコーディングを指定する必要があります。一般的な指定方法...

Linux のロード vmlinux デバッグ

gdb を使用してカーネル シンボルをロードする arm-eabi-gdb 出力/ターゲット/製品/...

MySQLの使い方の詳細な説明

目次1. はじめに2. 本文2.1 Where句の位置2.2 演算子2.3 NULL値1. はじめに...

MySQL テーブル自動増分 ID オーバーフロー障害レビュー ソリューション

問題: MySQLテーブル内の自動増分IDのオーバーフローによりビジネスブロックが発生した背景: t...

eject を使用せずに create-react-app の設定を変更する方法

1. イジェクトが推奨されないのはなぜですか? 1. eject を実行した後、どのような変化があり...