David Alsh
David Alsh

Reputation: 7649

How to capture Proxy "set" actions from a class constructor?

How do I trap actions where a property is set from inside a constructor?

class Foo {
  constructor() {
    setTimeout(() => this.value = 'value', 1000)
  }
}

const foo = new Foo()

const $foo = new Proxy(foo, {
  set(target, key, value) {
    if (target[key] === value) return
    target[key] = value
    console.log('Set', key, value)
    return true
  }
})

While here I am directly referencing Foo, in reality the Proxy implementation is inside a function with no knowledge of Foo, conversely Foo has no knowledge that it will be proxied. The solution should allow the usage of any class to be proxied, eg

const foo = new (ProxyWrapper(Foo))()
const bar = new (ProxyWrapper(Bar))()
const foobar = new (ProxyWrapper(Foobar))()

Upvotes: 0

Views: 79

Answers (1)

Jonas Wilms
Jonas Wilms

Reputation: 138267

You could create a Proxy on the prototype of the class:

class Foo {
  constructor() {
    setTimeout(() => this.value = 'value', 1000)
  }
}

const Trap = Object.assign(function() {},  { 
  prototype: new Proxy({}, {
    set(target, key, value) {
      target[key] = value;
      console.log("Set", target, key, value);
      return true;
    },
  }),
});

const $Foo = function () {
  return Reflect.construct(Foo, [], Trap);  
}

const foo = new $Foo();



setTimeout(() => console.log(foo), 1100)

As a function injecting the trap that could be written as:

function TrapMe(Super) {
  function Trapped() {
    return Reflect.construct(Super, [], Trapped); 
  }
  
  Trapped.prototype = new Proxy(Object.create(Super.prototype), {
    set(target, key, value) {
      target[key] = value;
      console.log("Set", target, key, value);
      return true;
    }
  });
  return Trapped;
}

const Foo = TrapMe(class Foo {
  constructor() {
    console.log("constructed");
    setTimeout(() => this.value = "value", 1000);
  }
});

new Foo();

Upvotes: 2

Related Questions