是否可以在打字稿中创建动态 getters/setters ?

Is it possible to create dynamic getters/setters in typescript?

我是 typescript 的新手,我正在尝试将我们的应用程序从 es2016 重写为 typescript。 我的任务是有一个 class 和数据 属性 并使数据对象中的每个元素可用作 class 属性.

我卡在这个 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);                                            
          }                                                                        
        },                                                                         
      });                                                                          
    }

使用 getter/setters 打字稿非常容易,但如果我可以动态创建它们,我会感到困惑?

    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'.

而且我不知道如何解决这个问题。

在打字稿中,您通常不需要动态创建具有方法和属性的对象。您可以创建 classes 的实例,或者使用界面输入数据。

如果您只想将加载的 (json) 数据转换为类型化数据,您可以使用描述 json 数据结构的接口。

接口描述actor数据的属性

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

从某处获取通用json数据

let data : any = getSingleActorData();

将actor输入到一个界面中,并将其放入一个actor数组中

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

现在您的 IDE 将允许您访问演员变量的名称和高度:

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

如果您确实想要一个完整的 'object' 和 getter 和 setter,您可以创建一个 Actor class 然后用您加载的数据实例化它:

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

然后你可以把你的json数据放在一个actor实例中:

actorData.push(new Actor(jsondata.name, jsondata.height));

感谢 https://github.com/epicgirl1998,她帮助我找到了解决方案。我将 post 放在这里:

the error is that the getter has a value parameter even though getters aren't passed any value

i replaced it with get: function() { return this.data[key]; }, and now the only error is that there's a super call in the class which is only needed if the class extends another class

also, this inside the accessors doesn't refer to the class instance, but using arrow functions for them should fix it

try this:

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);                                            
          }                                                                        
        },                                                                         
      });                                                                          
    }                                                                              
  } 
}