日本語版
最新ニュース
科学&テクノロジー

TypeScript についての別の考え方

ロビー・プルザン 2024 年 7 月 27 日 推定読書時間: 7.9メートル TypeScript 型システムは、型を操作する純粋な関数型言語と考えることができます。しかし、型を操作するとはどういう意味でしょうか?私にとって、型を要素のセットに解決して構築できるのは非常に便利です。このセットには、その型に割り当て可能なすべての実数値が含まれます。 TypeScript の中核となる構文は、通常のプログラミング言語で実際のセットを操作するのと同じように、任意のセット内の項目を操作する機能です。 TypeScript は 構造型システム名目上のものとは対照的に、この型構成要素の「設定」は、実際の型定義自体よりも役立つ場合があります (ただし、常にそうとは限りません)。 それぞれのタイプを集合として考えると、 リテラル- 実数値 - 構築することができます。文字列は、文字のすべての順列の無限の集合にすぎないと言えます。 number は、数字のあらゆる順列の無限集合です。 型システムをセットの処理のみを目的とした適切な関数型プログラミング言語として考え始めると、より高度な機能を少し簡単に使用できるようになります。 この記事では、typescript の機能のほとんどについて、次の観点から説明します: type は作成できるセットであり、typescript はセット上で動作する関数型プログラミング言語です。 注記 セットと型が同等だと言っているのではありません。 そうではありません。 TypeScript プリミティブを分解する 交差点(&) 交差点 (&)…

TypeScript についての別の考え方

1735961639
2025-01-02 17:42:00

ロビー・プルザン 2024 年 7 月 27 日

推定読書時間: 7.9メートル

TypeScript 型システムは、型を操作する純粋な関数型言語と考えることができます。しかし、型を操作するとはどういう意味でしょうか?私にとって、型を要素のセットに解決して構築できるのは非常に便利です。このセットには、その型に割り当て可能なすべての実数値が含まれます。

TypeScript の中核となる構文は、通常のプログラミング言語で実際のセットを操作するのと同じように、任意のセット内の項目を操作する機能です。

TypeScript は 構造型システム名目上のものとは対照的に、この型構成要素の「設定」は、実際の型定義自体よりも役立つ場合があります (ただし、常にそうとは限りません)。

それぞれのタイプを集合として考えると、 リテラル– 実数値 – 構築することができます。文字列は、文字のすべての順列の無限の集合にすぎないと言えます。 number は、数字のあらゆる順列の無限集合です。

型システムをセットの処理のみを目的とした適切な関数型プログラミング言語として考え始めると、より高度な機能を少し簡単に使用できるようになります。

この記事では、typescript の機能のほとんどについて、次の観点から説明します: type は作成できるセットであり、typescript はセット上で動作する関数型プログラミング言語です。

注記 セットと型が同等だと言っているのではありません。 そうではありません。

TypeScript プリミティブを分解する

交差点(&)

交差点 (&) は、このメンタル モデルが操作をより適切に推論するのに役立つ好例です。次の例を考えると

BarとBazの交差点です。ただし、最初は交差操作が次の方法で適用された可能性があります。

2 つのオブジェクト間の重なりを特定し、それを結果として取得します。でも…重なってない?左側 (LHS) には x のみが含まれ、右側 (RHS) には y のみが含まれますが、両方の数値が含まれます。では、なぜ交差により、これが許可される型が生成されるのでしょうか。

何が起こっているかを考えるより簡単な方法は、タイプを解決することです。 Bar そして Baz テキストでどのように見えるかではなく、構築したセットに反映されます。

の型を定義すると、 { y: number }、少なくともプロパティ y を含むオブジェクト リテラルの無限のセットを構築できます (y は数値です)。

注記: 「少なくともプロパティ y を持つオブジェクト タイプのセット」と述べたことに注目してください。そのため、一部のオブジェクト タイプには y 以外のプロパティが存在します。型を持つ変数がある場合 {y: number}オブジェクトの内部に y よりも多くのプロパティがあるかどうかは問題ではないため、TypeScript ではそれが許可されています。

型をそれが構築するセットで置き換える方法がわかったので、交差はより意味のあるものになります。

労働組合

確立した以前のメンタル モデルを使用すると、これは簡単です。2 つのセットを結合して新しいセットを取得するだけです。


型のイントロスペクション

TypeScript の管理者は、これが便利だと考えたので、言語にプリミティブを組み込み、これらのセットをイントロスペクトできるようにしました。たとえば、あるセットが別のセットのサブセットであるかどうかを確認し、true/false の場合に新しいセットを返すことができます。 extends キーワード。

の LHS セットかどうかを確認しているところ キーワードを拡張します RHS セットのサブセットです

これらを任意にネストできるため、これは非常に強力です。

しかし、型パラメータを使用し、型引数として共用体を渡すと、事態は奇妙になります。 TypeScript は、型パラメーターが使用されるときに、最初に共用体を構築されたセットに解決するのではなく、共用体のすべてのメンバーに対してサブセット チェックを個別に実行することを決定します。

したがって、型パラメータを使用するように前の例を少し変更すると、次のようになります。

Typescript は変換します Result の中へ:

作る Result 次のように解決します。

"T constructs a set containing only number" | "T constructs a set with items not included in number | null";

これは単に、ほとんどの操作においてこの方が便利だからです。ただし、タプル構文を使用して、TypeScript がこれを行わないよう強制することができます。

これは、条件付き型を共用体に適用するのではなく、たまたま内部に共用体を持つタプルに適用しているためです。

この特殊なケースは、型を常に構築したセットに即座に解決するメンタル モデルが完璧ではないことを示すため、重要です。

型マッピング

通常のプログラミング言語では、セットを反復処理して (ただし、言語内で実行できる場合もあります)、新しいセットを作成できます。たとえば、Python でタプルのセットをフラット化したい場合は、次のように実行できます。

nested_set = {(1,3,5,6),(1,2,3,8), (9,10,2,1)}
flattened_sed = {}
for tup in nested_set:
  for integer in tup:
    flattened_set.add(integer)

私たちの目標は、これを TypeScript 型で行うことです。次のように考えてみます。

Array

数値を含む配列のすべての順列のセットとして:

何らかの変換を適用して、各項目から数値を選択し、セットに配置したいと考えています。

命令型構文を使用する代わりに、typescript で宣言的にこれを行うことができます。例えば:

このステートメントは次のことを行います。

  • T がセットのサブセットであるかどうかを確認します Array 構成要素 (R はまだ存在しないため、any で置き換えます)
    • そうである場合、セット T 構造内の各配列について、すべての配列の項目を R’ と呼ばれる新しいセットに配置します。
      • R’ を構築する型を推測し、その型を R 内に配置します。R は真のブランチでのみ使用できます。
      • 最終的な型として R を返します
    • そうでない場合は、エラー メッセージを入力してください

注記 これは、推論の実装方法の仕様に基づくものではなく、推論がセットのメンタル モデルでどのように機能するかを推論するための単なる方法です。

このプロセスは次のように視覚的に説明できます。

このメンタル モデルでは、単語を使用する TypeScript infer 実際には意味があります。私たちが作成したセット (R`) の作成方法を記述するタイプを自動的に見つけます。

型変換にマップされた型

TypeScript を使用すると、セットが何かに似ているかどうかを非常に正確にチェックし、それに基づいてマップすることができる方法について説明しました。ただし、タイプによって構築されたセット内の各項目がどのように見えるかをもっと表現できれば便利です。このセットをうまく説明できれば、必要なものは何でも作ることができます。

マップされた型はこの好例であり、非常に単純な初期使用法を持ち、セット内のすべての項目をマップしてオブジェクト型を作成します。

例えば:


最後のステップは、オブジェクト タイプをセットにマッピングし直すことです。

文字列のサブセットをマッピングすることもできます。

ここではセット上にマッピングします ["string", "bar"] オブジェクトタイプを作成するには => {string: "string", bar: "bar"} 次に、構築可能なセットを記述します。

オブジェクト型のキーと値に対して任意の型レベルの計算を実行できます。

注記: never 空のセットです – セット内に値が存在しません – したがって、型を持つ値は決して使用できません 一度もない 何かを割り当てられる

ここでセットをマッピングしました ["string", "bar"] 新しいタイプを作成するには =>

{["IM A s"]: "s", ["IM A b"]: "b"}

反復ロジック

セットに対して何らかの変換を実行したいが、その変換を表現するのが非常に難しい場合はどうなるでしょうか。次の項目に移動する前に、内部計算を任意の回数実行する必要があります。ランタイム プログラミング言語では、簡単に for ループに到達します。ただし、TypeScript の型システムは関数型言語であるため、再帰に手を伸ばすことになります。

さて、まずは…(笑)何だろう。これは非常識に見えるかもしれませんが、実際には単なる高密度のコードであり、複雑ではありません。 TypeScript ランタイム バージョンを作成して、何が起こっているかを拡張してみましょう。