5

I'm proxying methods using the following wrapper:

  public static wrap(target) {
    function construct(constructor, args) {
      const c: any = function(this) {
        return constructor.apply(this, args);
      };

      c.prototype = constructor.prototype;
      return new c();
    }

    const f = (...args) => {
      const instance = construct(target, args);

      const descriptors = getMethodDescriptors(target, instance);

      return new Proxy<T>(
        instance,
        new SomeProxyHandler(descriptors)
      );
    };

    f.prototype = target.prototype;
    return f;
  }

This has worked well when wrapping classes which are compiled down to ES5 but now I'm trying to target ES6 I'm getting errors at constructor.apply(this, args) saying that:

TypeError: Class constructor OneOfMyClasses cannot be invoked without 'new'

How can I fix this code so wrap can proxy classes whatever the JavaScript target and maintain the correct prototype chain?

Tim
  • 6,485
  • 2
  • 42
  • 81
  • 1
    related: [How to use a Proxy in javascript to capture a constructor while maintaining the prototype chain?](https://stackoverflow.com/q/49738211/1048572) and [TypeError when trying to Proxy a ES6 class constructor](https://stackoverflow.com/q/43104420/1048572) – Bergi Feb 25 '19 at 10:08

1 Answers1

7

The easiest way would be spread syntax

const instance = new target(...args);

but you can also use Reflect.construct:

const instance = Reflect.construct(target, args);

This will even be necessary if your wrapped classes are supposed to be extensible, you then will have to make use of new.target:

const instance = Reflect.construct(target, args, new.target);

Btw, your f wrapper should be a proper function not an arrow function, as those cannot be called with new (and don't have new.target). Or maybe even simpler (working better with static methods and inheritance), just wrap the whole target class itself in a Proxy and use its construct trap.

Bergi
  • 513,640
  • 108
  • 821
  • 1,164