Search code examples
typescriptecmascript-6proxygetter-setter

How to trap ES6 getter with ES6 proxy?


I use a proxy to monitor all property accesses on a class's instances, like in the following example:

class Person {
  public ageNow: number;

  public constructor(ageNow: number) {
    this.ageNow = ageNow;

    const proxy = new Proxy(this, {
      get: (target, property) => {
        console.log(property);
        return target[property as keyof typeof target];
      },
    });
    return proxy;
  }

  public ageIn10Years1() {return this.ageNow + 10;}
  public get ageIn10Years2() {return this.ageNow + 10;}
}

Now when I do e.g.

const peter = new Person(18);
console.log(peter.ageIn10Years1());

it prints 'ageInYears1', 'ageNow' and 28 (in that order), as I expect.

However, when I do

console.log(peter.ageIn10Years2);

i.e. use a getter, it also prints 'ageInYears2' and 28 but no longer 'ageNow', although that property is clearly accessed.

Why is that and how can I fix it?


Solution

  • The getter use the original object not the proxy that you created

    One solution is to call the getter function on the proxy.

    
    class Person {
      public ageNow: number;
    
      public constructor(ageNow: number) {
        this.ageNow = ageNow;
        const proxy = new Proxy(this, {
          get: (target, property) => {
            const descriptor = Object.getOwnPropertyDescriptor(Person.prototype, property);
            if (descriptor && typeof descriptor.get === 'function') {
                console.log("calling",property);
              return descriptor.get.call(proxy);
            } else {
              console.log(property);
              return target[property as keyof typeof target];
            }
          },
        });
        return proxy;
      }
    
      public ageIn10Years1() {return this.ageNow + 10;}
      public get ageIn10Years2() {return this.ageNow + 10;}
    }
    
    
    const peter = new Person(18);
    console.log(peter.ageIn10Years1());
    console.log(peter.ageIn10Years2);