Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 315
Vlad Avatar asked Jul 21 '17 11:07

Vlad


People also ask

What is getter setter in angular?

The getters and setters allow you to control the access to the properties of a class. For each property: A getter method returns the value of the property's value. A getter is also called an accessor. A setter method updates the property's value.

Are getters and setters always public?

In general, they should be public. If they are private they can only be called from within your class and, since you already have access to the private variables within your class, are redundant. The point of them is to allow access to these variables to other, outside, objects.


1 Answers

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);                                            
          }                                                                        
        },                                                                         
      });                                                                          
    }                                                                              
  } 
}
like image 142
Vlad Avatar answered Oct 03 '22 22:10

Vlad