プロキシを使用した型分析

Node.jsモジュールの次の一連のテストを説明する過程で、「タイプチェックを繰り返します」と思うようになりました。 クラスメソッドの各パラメーター、セッターを使用して設定された各プロパティをチェックする必要があります。 もちろん、チェックを実装するコードですべてを単純に打ち込んだり、補完したり、デコレータですべてを記述したりできます。 しかし、今回は少し違うことをします。







いくつかの感情とお菓子






ES6仕様の到来とさまざまなエンジンへの実装により、多くの驚くべきことがもたらされます。私の考えでは、この休暇を別にしておくのは愚かです 新しい仕様をより深く掘り下げ、生活を少し簡素化したいという欲求を武器に、 Proxyのようなすばらしいものを使用して型分析を実装してみましょう。 もちろん、クラス、マップ、矢印関数など、Node.jsバージョン6.1.0でネイティブにサポートされている他のES6パンを使用します。







使い方






  1. npm i typedproxy



    をインストールしnpm i typedproxy



    。 モジュールを接続します







     // 1. const Typed = require('typedproxy');
          
          





  2. クラスを作成し、静的メソッド、メソッド、静的プロパティおよびプロパティを使用します。 メソッドとセッターのパラメーターを記述するとき、特別な構文を使用します。







  3. つまり、メソッドで使用される各パラメーター名(静的を含む)は、タイプに対応する文字のシーケンスで始まる必要があります。 型は、いわゆる型オブジェクトのプロパティにすぎません。 プロパティの名前は型名に対応し、プロパティの値は渡された値の検証を実装する関数です。 つまり、任意の数の変数タイプを定義できます。







  4. タイプオブジェクトの詳細。 このオブジェクトには、使用されている、またはクラスで使用する予定のすべてのタイプがリストされている必要があります。 指定した条件を満たすことを忘れた場合-これは、進行中のRangeErrorにつながります。

    そして、原則を理解するためのコードはほとんどありません







     // 2.  ,   . class TestClass { // 3.       myRange. constructor(myRangeValue){ this.value = myRangeValue; } }; // 4.   .      myRange. const types = { 'myRange' : (value) => { if(value < 0 || value > 10) { throw new TypeError(`parameter must be more than 0 and less than 10, not ${value}`); } } };
          
          





    myRangeの値はパラメーターの名前であり、その検証は、対応する名前myRangeを持つtypeオブジェクトのプロパティ決定されます。







  5. ここで、型チェックを有効にするには、クラスを典型化する必要があります(この概念は、使用するモジュールのフレームワーク内で使用されます。ここで仕様から概念を引き寄せるべきではありません)。 そして、前述のTestClassクラスと型を使用してこのようにします。







     // 5. const TypedTestClass = new Typed(TestClass, types);
          
          





  6. 上記では、新しいTypedTestClassクラスを取得しました。これは、実際にはProxyのインスタンスですが、それについては後で詳しく説明します。 TestClassの代わりに使用します。つまり、クラス自体とそのインスタンスの両方のインスタンスを作成し、静的メソッドを呼び出します。 一般に、元のTestClassでやりたいことをすべて実行します。







     // 6.    . /*ok -    */ const instance1 = new TypedTestClass(5); /*TypeError -     */ const instance2 = new TypedTestClass(11); /*RangeError -           */ const instance3 = new TypedTestClass(); /*RangeError -           */ const instance3 = new TypedTestClass(1, 2);
          
          





    ご覧のとおり、間違ったパラメータータイプを渡すとエラーが発生します。 間違った数のパラメーターを渡すと(タイプの要件を満たしているかどうかに関係なく)エラーも発生します。







  7. 使用上の注意:

    7.1。 継承を使用する場合(たとえばextends



    )、チェーン全体ではなく最終クラスを典型化する必要があります。 まあ、第一に、なぜ余分な変数と余分な作業があるのか​​、そして第二に、何もうまくいかないでしょう。

    7.2。 デフォルトの設定を使用する場合、このモジュールあなたには適していません(現在作業中です)。


すべて一緒に
 // 1. const Typed = require('typedproxy'); // 2.  ,   . class TestClass { // 3.       myRange. constructor(myRangeValue){ this.value = myRangeValue; } }; // 4.   .      myRange. const types = { 'myRange' : (value) => { if(value < 0 || value > 10) { throw new TypeError(`parameter must be more than 0 and less than 10, not ${value}`); } } }; // 5. const TypedTestClass = new Typed(TestClass, types); // 6.    . /*ok -    */ const instance1 = new TypedTestClass(5); /*TypeError -     */ const instance2 = new TypedTestClass(11); /*RangeError -           */ const instance3 = new TypedTestClass(); /*RangeError -           */ const instance3 = new TypedTestClass(1, 2);
      
      





仕組み






千語以上のコードと数枚の写真を理解している人のために:テストプロジェクトはこちらです。 これが言葉でどのように機能するかを理解したいという願望を持ち続けている人々のために、私はさらに説明しようとします。







パラメーター名とタイプを説明するオブジェクトの関係:



関係







図からわかるように、また上記で述べたように、メソッドパラメータの名前とクラスで使用されるとの間に直接的な関係を確立する必要があります。 つまり、パラメーター名は、タイプに一致する一連の文字で始まる必要があります。

これは、関数が型チェックを実行するために必要です(これについては後ほど説明します) 。 原則として、この関数の実装が適切でない場合は、型付きクラスを作成するときに3番目のパラメーターを渡すことができます。







 const Typed = require('typedproxy'); class TestClass { // ... }; const types = { // ... }; const TypedTestClass = Typed(TestClass, types, (types, someFunction, ...args) => {/*   */});
      
      





作業の概略図



ワーキングスキーム







クラスが入力されると、新しいプロキシが作成されて返されます。 このプロキシは、型分析を実行するクラスです。 その本質は、型チェック機能を使用して静的メソッドの呼び出しをインターセプトしたり、新しいインスタンスを作成したりするために必要なトラップを決定することです。







型チェック機能(図の緑と赤の四角)は次のように機能します。







  1. 使用される型のリスト、関数、および関数に渡されるパラメーターを取得します。
  2. (正規表現を使用して)関数が受け入れることを期待するパラメーター名を取得します。
  3. 渡され、受け入れられると予想されるパラメーターの数が同じかどうかを確認します。 別の方法で例外をスローする場合。
  4. 予想されるパラメーターの名前が、いずれかのタイプに一致する一連の文字で始まるかどうかを確認します。 一致しない場合、例外をスローします。
  5. 適切なタイプの機能を実行します。


新しいプロキシには、 getset、およびconstructの 3つのトラップのみがあります。







  1. get-静的メソッドにアクセスすると、型チェックを実行するプロキシを返し、ソースクラスの静的メソッドにリダイレクトします。
  2. set-クラスの静的プロパティの値を変更しようとするときに、セッターが存在する場合、タイプチェックを実行し、指定された値のみを設定します。
  3. 構成-new演算子を使用して型付きクラスを呼び出すと、コンストラクターに渡されるパラメーターの型がチェックされます。 その後、元のクラスのインスタンスと、それに基づいたプロキシを作成します(上記の方法1および2と同様に機能する2つのgetおよびsetフックを使用)。


もちろん、非常に怪しいように見えますが、実際はそうです。 このモジュールには、改善と修正が必要なアイデアのみが表示されます。 パフォーマンスについても考えたくありません。むしろ、利便性と時間の節約のために、パフォーマンスを犠牲にして使用することができます。








All Articles