TypeScript class decorator that modifies object instance

6k views Asked by At

I'm making a plugin for Aurelia and need a class decorator that

  1. adds attributes to the new object instance, and
  2. calls an external function with the new object as an argument.

I've looked through examples, and so far I've put together ("pseudo-ish" code)

return function addAndCall(target: any): any {
    var original = target;

    var newConstructor = function (...args) {
        original.apply(this, args);
        this.newAttribute = "object instance value";
        ExternalModule.externalFunction(this);
    };

    newConstructor.prototype = Object.create(original.prototype);
    newConstructor.prototype.constructor = original;

    return <any>newConstructor;
}

but

  • I'm not entirely clear on the details here (or what is actually needed), and
  • it might not work properly since I'm getting Aurelia errors when using objects instantiated from classes with this decorator (and I suspect it's my decorator rather than the Aurelia framework that's buggy).

Any help and explanation would be greatly appreciated!

2

There are 2 answers

1
William Addington On

Why not just assign those properties to the prototype, and subsequently assign to the instance on first invocation

// decorator
function addAndCall(cb: Function, newField: string) {
  // cb is now available in the decorator
  return function(ctor: Function): void {

    Object.defineProperty(ctor.prototype, newField, {
      value: function(...args: any[]) {
        return Object.defineProperty(this, newField, {

          value: function(...args: any[]) {
            console.log(newField, ...args);
          }

        })[newField](...args);
      }
    });
    cb(ctor);
  }
}

let callMe = (decoratedCtor) => console.log(decoratedCtor);
@addAndCall(callMe, 'propertyName')
class AddToMe {}

let addToMe = new AddToMe();
(<any>addToMe).propertyName(1, 2);
0
Nitzan Tomer On

Here's a working version:

function addAndCall(target: any) {
    var original = target;

    function construct(constructor, args) {
        var c: any = function () {
            this.newAttribute = "object instance value";
            ExternalModule.externalFunction(this);
            return constructor.apply(this, args);;
        }

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

    var f: any = function (...args) {
        return construct(original, args);
    }

    f.prototype = original.prototype;
    return f;
}

(code in playground)