2015-11-25 6 views
8

私はフロントエンド/バックエンドのデータ構造間の単純なマッピングを構築しています。デコレータで非プロトタイプにプロパティを割り当てる

function ApiField(
    apiKey: string, 
    setFn: (any) => any = (ret) => ret, 
    getFn: (any) => any = (ret) => ret 
) { 
    return function (target: AbstractModel, propertyKey: string) { 
     target.apiFieldsBag = target.apiFieldsBag || {}; 
     _.assign(
      target.apiFieldsBag, 
      { 
       [propertyKey]: { 
        apiKey: apiKey, 
        setFn: setFn, 
        getFn: getFn 
       } 
      } 
     ); 
    }; 
} 

そして、これは私がそれを使用する方法です::

class AbstractCar { 
    @ApiField('id') 
    public id: string = undefined; 
} 

class BMW extends AbstractCar { 
    @ApiField('cylinders') 
    public cylinderCount: number; 
} 

class VW extends AbstractCar { 
    @ApiField('yearCompanyFounded') 
    public yearEstablished: number; 
} 

私が見ている問題があることの代わりに、私は次のようなデコレータを作成したことを行うために実際のオブジェクトは、それが常にそのプロトタイプだデコレータに渡される:

__decorate([ 
    ApiField('yearCompanyFounded') 
], VW.prototype, "yearEstablished", void 0); 

私はデコレータでインスタンスにコンテンツを割り当てるいて、それは常にプロトタイプに装着されていることを意味していますつまり、VWインスタンスのみを定義したいプロパティは、AbstractCarクラスとBMWクラス(この例ではyearEstablished)で使用できます。これにより、同じ名前で2つの異なるクラスの異なるAPIフィールドを持つことは不可能になります。

この動作を回避する方法はありますか?

+0

!!!!:ここ

は、これを行うの1つの方法を示しシンプルな例です – Arjun

+0

'_.assign(')の代わりに 'target.apiFieldsBag ='は必要ありません。また、 '_.assign()の代わりにES6' Object.assign() ' –

+0

ええ、私はもう一度質問を見ていると思いました。とにかく頭のおかげで:) –

答えて

4

今のところ、すべての3つのクラスはにプロパティを追加します同じオブジェクト。これを解決する鍵はクローンのオブジェクトtarget.dataにあります。そのため、各クラスは同じオブジェクトを参照するすべてのオブジェクトではなく、別のオブジェクトを使用しています。 ... ECMAScriptの7

function ApiField(str: string) { 
    return function (target: any, propertyKey: string) { 
     // I tested with Object.assign, but it should work with _.assign the same way 
     target.data = _.assign({}, target.data, { 
      [propertyKey]: str 
     }); 
    }; 
} 

class AbstractCar { 
    @ApiField("car") 
    public carID; 
} 

class BMW extends AbstractCar { 
    @ApiField("bmw") 
    public bmwID; 
} 

class VW extends AbstractCar { 
    @ApiField("vw") 
    public vwID; 
} 

AbstractCar.prototype.data; // Object {carID: "car"} 
BMW.prototype.data;   // Object {carID: "car", bmwID: "bmw"} 
VW.prototype.data;   // Object {carID: "car", vwID: "vw"} 
+0

事は、私はBMWクラスAbstractCarからのデータを継承したいです –

+0

@justNikああ、大丈夫です。私はそれのために働く何かで私の答えを更新しました。 –

+0

甘い、ありがとう!このような複雑な見た目は、このような一般的なjavascriptの問題に沸きます。木のフォレストを逃した話 –

4

問題は、クラス内のpublicは標準のJavaScriptではないことです。これはTypeScriptが行うものだけです。したがって、あなたは何かが将来壊れるかもしれないので、あなたは慎重でなければなりません。

一つの可能​​性は(IINM、apiFieldsBagthisにオブジェクトリテラルによって作成されたオブジェクトから転送されなければならない)インスタンスのプロパティを追加するObject.assign()を使用することです:

class AbstractCar { 
    constructor() { 
     Object.assign(this, { 
      @ApiField('id') 
      id: undefined, 
     }); 
    } 
} 
+0

私は実際にtypescriptを使用していますので、' public'を使うのはいいでしょう:)しかし、私はあなたの解決策を試してみるつもりです –

+1

@justNik 'public'はTypeScriptです。 'public foo = x'の問題は、それが実際のエンティティ(例えばプロパティ)として存在しないこと、コンストラクタ内の割り当てにコンパイルされることです。したがって、どのような装飾が必要であるかは明確ではない。というのも、ATMはクラスとプロパティだけを装飾できるからである。 –

+0

@justNik私はちょうど装飾された 'public'がコンパイルされているコードを見ました。そしてTypeScriptは実際にプロトタイプのプロパティを飾ります。それはバグです、IMO(コンストラクタで 'this 'のプロパティを飾るべきです) - あなたはバグレポートを提出したいかもしれません。 –

関連する問題