Is there a way to dynamically add getter to a class in javascript/typescript?

Viewed 42

I need some guidance or expert knowledge on JavaScript capabilities. I'm studying TypeScript ATM, specifically decorators functionality.

Is there a way to dynamically add a getter method to a Prototype object so that it is executed in place of the plain property access on an instance.

Here's some code for example:

class Car {
  @decorate
  color: string = 'red';

  drive(): {
    return 'Driving';
  }
}


function decorate(target, key): void {
  //would be cool to add a getter and update
  //the prototype in target to contain such getter
  //I know this won't work, but to get the idea.
  target[key] = get function() {
    console.log(`Accessing property: ${key}`);
    return eval(`this.${key}`)
  }
}

Then, when I would create and object and try to access .color

const car = new Car();
car.color;

ideally I would see at the console

Accessing property: color
2 Answers

You can use Proxy in JavaScript. As MDN states, it allows you to create an object that can be used in place of the original object, but which may redefine fundamental Object operations like getting, setting, and defining properties. Proxy objects are commonly used to log property accesses, validate, format, or sanitize inputs, and so on.

class Car {
  color = 'red'

  drive() {
    return 'Driving'
  }
}

const proxy = new Proxy(new Car(), {
   get(target, key) {
      console.log(`Accessing property: ${key}`);
      return Reflect.get(target, key)
   }
})

proxy.color // prints "Accessing property: color" and returns value of color.

In plain javascript you could use Object.defineProperty to dinamicaly add getters and setters to object.

That was my inital comment.

If you will to decorate only certain fields of the object then MDN example would be the easiest way to this properly:

const o = {a: 0};  
Object.defineProperty(o, 'b', { get() { return this.a + 1; } });  
console.log(o.b) // Runs the getter, which yields a + 1 (which is 1)  
Related