web-dev-qa-db-ja.com

タイプスクリプトで動的なゲッター/セッターを作成することは可能ですか?

私はTypeScriptを初めて使用し、アプリケーションをes2016からTypeScriptに書き直そうとしています。私の仕事は、データプロパティを持つクラスを作成し、データオブジェクトの各要素をクラスプロパティとして使用できるようにすることです。

私はこのjavascriptコードで立ち往生しています:

    for(let key in this.data) {                                                    
      Object.defineProperty(this, key, {                                           
        get: function(value:any) { return this.data[key]; },                       
        set: function(value:any) {                                                 
          if (this.data[key] !== value) {                                          
            this.data[key] = value;                                                
            this.updatedKeys.Push(key);                                            
          }                                                                        
        },                                                                         
      });                                                                          
    }

TypeScriptでゲッター/セッターを使用するのは非常に簡単ですが、動的に作成できると混乱しますか?

    interface IData {                                                               
      id: number;                                                                   
      [propName: string]: any;                                                      
    }                                                                               

    class Model  {                                                 

      protected updatedKeys:string[] = [];                                          

      baseUrl:string = null;                                                        
      data:IData;                                                                   
      fields:IData;

      constructor(data:IData={id:null}, fields:IData={id:null}) {                      
        super()                                                                        
        this.data = data;                                                              
        this.fields = fields;                                                                                                     

        for(let key in this.data) {                                                    
          Object.defineProperty(this, key, {                                           
            get: function(value:any) { return this.data[key]; },                       
            set: function(value:any) {                                                 
              if (this.data[key] !== value) {                                          
                this.data[key] = value;                                                
                this.updatedKeys.Push(key);                                            
              }                                                                        
            },                                                                         
          });                                                                          
        }                                                                              
      } 
    }

tsc -t ES2016 --lib "es2016","dom" models.ts

このエラーが発生します:

models.ts(33,40): error TS2345: Argument of type '{ get: (value: any) => any; set: (value: any) => void; }' is not assignable to parameter of type 'PropertyDescriptor & ThisType<any>'.
  Type '{ get: (value: any) => any; set: (value: any) => void; }' is not assignable to type 'PropertyDescriptor'.
    Types of property 'get' are incompatible.
      Type '(value: any) => any' is not assignable to type '() => any'.

そして、私はこの問題を取り除く方法がわかりません。

8
Vlad

https://github.com/epicgirl1998 のおかげで、彼女は私が解決策を見つけるのを手伝ってくれました。ここに投稿します:

エラーは、ゲッターに値が渡されていなくても、ゲッターに値パラメーターがあることです。

getに置き換えました:function(){return this.data [key]; }、そして今、唯一のエラーは、クラスが別のクラスを拡張する場合にのみ必要なスーパー呼び出しがあるということです

また、アクセサー内のこれはクラスインスタンスを参照していませんが、それらに矢印関数を使用すると修正されるはずです

これを試して:

interface IData {                                                               
  id: number;                                                                   
  [propName: string]: any;                                                      
}                                                                               

class Model  {                                                 

  protected updatedKeys:string[] = [];                                          

  baseUrl:string = null;                                                        
  data:IData;                                                                   
  fields:IData;

  constructor(data:IData={id:null}, fields:IData={id:null}) {                      

    this.data = data;                                                              
    this.fields = fields;                                                                                                     

    for(let key in this.data) {                                                    
      Object.defineProperty(this, key, {                                           
        get: () => { return this.data[key]; },                       
        set: (value:any) => {                                                 
          if (this.data[key] !== value) {                                          
            this.data[key] = value;                                                
            this.updatedKeys.Push(key);                                            
          }                                                                        
        },                                                                         
      });                                                                          
    }                                                                              
  } 
}
10
Vlad

TypeScriptでは、通常、メソッドとプロパティを使用してオブジェクトを動的に作成する必要はありません。クラスのインスタンスを作成するか、インターフェイスを使用してデータを入力します。

ロードされた(json)データを型付きデータに変換するだけの場合は、jsonデータの構造を記述するインターフェイスを使用できます。

インターフェースはアクターデータのプロパティを記述します

interface Actor {
    name: string;
    height: number;
}

どこかから一般的なjsonデータをフェッチします

let data : any = getSingleActorData();

アクターをインターフェースに入力し、アクター配列に配置します

let actorData : Actor[] = [];
actorData.Push(data as Actor);

これで、IDEにより、アクター変数の名前と高さにアクセスできるようになります。

console.log(actorData[0].name);

ゲッターとセッターを備えた完全な「オブジェクト」が必要な場合は、Actorクラスを作成し、ロードしたデータを使用してインスタンス化できます。

class Actor {
    private _name:string;
    private _height:string;
    get name {}
    set name {}
    get height {}
    set height {}
    constructor(name:string, height:number){
    }
}

そして、jsonデータをアクターインスタンスに配置できます。

actorData.Push(new Actor(jsondata.name, jsondata.height));
0
Kokodoko