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

坚强是说给别人听的谎言 提交于 2019-12-12 08:08:10

问题


I'm new in typescript, and i'm trying to rewrite our application from es2016 to typescript. My task is to have a class with data property and make each element from data object available as class property.

I get stuck on this javascript code:

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

It is pretty easy to use getter/setters for typescript, but i get confused if i can create them dynamically?

    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

WIll give this error:

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

And i don't know how to get rid of this problem.


回答1:


thanks to the https://github.com/epicgirl1998, she helped me to find the solution. I'll post it here:

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



回答2:


In typescript, you generally don't need to create objects with methods and properties dynamically. You either create instances of classes, or you type your data using an interface.

If all you want is to convert loaded (json) data to typed data, you can use an interface that describes the structure of your json data.

interface describes the properties of actor data

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

fetch generic json data from somewhere

let data : any = getSingleActorData();

type the actor to an interface and put it in an actor array

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

Now your IDE will allow you to access the name and height of the actor variable:

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

If you do want a complete 'object' with getters and setters you can create an Actor class and then instantiate it with the data you loaded:

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

And then you can put your json data in an actor instance:

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


来源:https://stackoverflow.com/questions/45236274/is-it-possible-to-create-dynamic-getters-setters-in-typescript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!