tamtakoe
tamtakoe

Reputation: 237

How to make class decorator which works correct with DI

I want to decorate my class

@params({
  url: '/books'
})
@Injectable()
export class BooksResource {
  constructor(@Inject(HttpClient) protected http: HttpClient) {}
  get() {
    return this.http.get(this.url)
  }
}

by custom @params decorator

function params(options) {
  return (target) {
    const original = target;

    function construct(constructor, args) {
      const c: any = function () {
        return constructor.apply(this, args);
      };
      c.prototype = constructor.prototype;
      return new c();
    }

    const newConstructor: any = function (...args) {
      const instance = construct(original, args);

      instance.url = options.url;

      return instance;
    };

    newConstructor.prototype = target.prototype;

    return newConstructor;
  }
}

I tried one million variants with custom constructor but they don't work with injected arguments

Original constructor works nice

function params(options) {
  return (target) {
    return target
  }
}

How to fix it? Playground: https://embed.plnkr.co/opnY3y/

Upvotes: 2

Views: 1217

Answers (1)

yurzui
yurzui

Reputation: 214047

Angular is quite strict to inheritance. I'm not sure whether it will work with AOT but in your plunker you can use the following decorator:

function params(options) {
  return (target) => {
    const original = target;

    const newConstructor: any = function newCtor(...args) {
      const c: any = function childConstuctor() {
        return original.apply(this, arguments);
      };
      c.prototype = Object.create(original.prototype);
      const instance = new c(...args);

      instance.url = options.url;

      return instance;
    };

    newConstructor.prototype = Object.create(target.prototype);
    return newConstructor;
  }
}

Note: function names are required

Forked Plunker

Upvotes: 3

Related Questions