TypeScriptのデコレータを使用したJSON検証

私は静的型が大好きなので、TypeJSはNodeJSまたはブラウザベースのJSを使用する際に不可欠なツールになりました。



サービスの義務により、JSONで多くの作業を行う必要がありますが、ここではTypeScript型システムは何の助けにもならず、コンパイラーがエラーを報告せず、JSON.parseが型Anyを返すため、干渉さえします。 さらに、TypeScriptは作業の詳細のためにリフレクションをサポートしていません。つまり、既存のコードに基づいて型を確認する方法はありません。 また、最近まで、メタプログラミングの手段はまったくありませんでした。



多くの場合、到着したJSONオブジェクトの正当性をチェックすると、クラスコンストラクター内の巨大なコード、または同じ構成ファイルになります。 しかし、最終的に、デコレータTypeScript 1.5に 登場しました。



デコレータを使用すると、 宣言中にクラス、メソッド、プロパティ、またはパラメータでいくつかの操作を実行できますが、装飾されたオブジェクトに関する追加情報を送信することもできます。 これを利用しました。



次のようになります。



class X extends Model { @prop({ type: PropType.Array, arrayProp: { type: PropType.Number } }) a; } enum Enum1 { V1, V2, V3 } class MyClass extends Model { @prop({ type: PropType.Object, class: X }) prop1; @prop({ type: PropType.String }) propString; @prop({ type: PropType.Enum, class: Enum1 }) b: Enum1; } class TestString extends Model { @prop({ type: PropType.String }) prop: string; }
      
      





型を指定するときに少し重複していることが判明しましたが、これは純粋に型チェックのためにクラスシステムを個別に記述するよりもはるかに害が少ないです。



挑戦する



ネストされたオブジェクト(独自の型を持つ)を階層的にサポートしながら、フィールドでエラーなしでJSONオブジェクトから本格的なTypeScriptオブジェクトを取得する必要があります。 ルートがプレーンオブジェクトではないJSONでの作業を実装しませんでした。 必要はありませんでした。



JSONからの出力で取得したい主なタイプ:



解決策



実装のために、プロパティデコレータと、フィールドをチェックするすべてのクラスが継承する特別なModelクラスを作成しました。 クラスを定義するとき、デコレータで宣言されたすべてのフィールド(タイプ、必須など)に関する情報が特別なフィールドに入力されます。 ところで、継承を使用することはできませんが、クラスデコレータ(@jsonableなど)を作成します。



文字列-実際のJSオブジェクト文字列で単純にチェックされます。 数値とブール値にはisCastingパラメーターを指定する機能があります。この場合、値を数値にキャストできるか、ブール値を使用できるかどうかがチェックされます。



オブジェクト-オブジェクトがプレーンオブジェクトであるかどうかがチェックされ、特別なパラメータークラスが指定されている場合はインスタンスが作成され、クラスがモデルを継承する場合はそのフィールドが適宜チェックされます。

配列-JS-Array +列挙値のタイプを指定する機能を確認します。 タイプごとに各値が個別にチェックされます。

列挙- クラスパラメータが指定されている場合(この場合は列挙への参照)、必要な値がこの列挙に存在するかどうかがチェックされます。 JSONは(enumの定義のように)テキストで指定されます。



ここではコードを提供しません。非常に簡単です。github投稿しました 。 上記のリストで説明したクラスの使用例を次に示します。



 var a = new MyClass({ propString: "test1", prop1: { a: [1, 2, 3] }, b: "V1" }); console.assert(a.prop1 instanceof X); console.assert(ab === Enum1.V1, "Invalid JSON"); console.assert(a.propString === "test1"); try { new TestString({ prop: 123 }); console.assert(false, "Not check string field"); } catch (e) { } try { new MyClass({}); console.assert(false, "Not check required field"); } catch (e) { }
      
      





私が言ったように、これはこれまでのところプロトタイプであり、戦闘モードには参加していませんが、同様のソリューションの基礎やデコレーターを使用する可能性を提供します。



PS最近、HabréでGoのシンプルさに関する記事が公開されました- 「Goのシンプルさは難しい」 。 そのため、TypeScriptの新しいキーシンボル@を使用することで、コードの量をときどき減らすことができ、すぐにそれを思い出しました。 そして、矢印関数の外観に私はどれほどうれしかったです! 非同期、待機(はい、はい、2つの新しい単語)を楽しみにしています。これにより、大量の、いつ、解決、拒否などを取り除くことができます。



All Articles