Search code examples
angulartypescriptdecorator

Angular decorator don't works on this scope


With a custom decorator I want inject into a method a property with another method inside. The decorator:

function test() {
  return function(target, key, descriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function(...args: any[]) {
      Object.defineProperty(this, "foo", {
        value: () => console.log("foo fired!"),
        enumerable: false,
        writable: false
      });
      return originalMethod.apply(this, args);
    };
    return descriptor;
  };
}

usage:

import { Component} from "@angular/core";

@Component({
  selector: "my-app",
  template: `<button (click)="bar()">Test</button>`,
})
export class AppComponent {

  @test()
  bar() {
    console.log("bar fired!");

    const self = this;
    (self as any).foo(); // this works!

    (this.bar as any).foo(); // this doesn't works!
  }
}

see online https://stackblitz.com/edit/angular-ivy-dhfasr?file=src%2Fapp%2Fapp.component.ts

I don't understand because this works:

@test()
bar() {
    const self = this;
    (self as any).foo();
}

but this doesn't works (Error: this.bar.foo is not a function):

@test()
bar() {
    (this.bar as any).foo(); // Error: this.bar.foo is not a function
}

what I'm doing wrong?


Solution

  • inside of bar function when you call it this keyword references to AppComponent instance. it is expected that you added foo element to AppComponent when you call bar method.

    if you still want to access it like (this.bar as any).foo(); then define foo field on a bar, not this

    function test() {
      return function(target, key, descriptor) {
        const originalMethod = descriptor.value; // no point of overriding it. we just add a field
        Object.defineProperty(originalMethod, "foo", {
          value: () => console.log("foo fired!"),
          enumerable: false,
          writable: false
        });
        return descriptor;
      };
    }