Использование декораторов вместе с конструкторами классов - PullRequest
1 голос
/ 30 октября 2019

Я пытаюсь использовать декораторы в классе, который инициализируется параметром, но значение, установленное в конструкторе, не определено, когда декоратор применяется к моей функции. Пожалуйста, посмотрите пример игрушки ниже:

function someDecorator() {
  return (target: any, _2: any, descriptor: PropertyDescriptor) => {
    const func = descriptor.value.bind(target);
    descriptor.value = () => {
      console.log('Doing decorator stuff!');
      func();
    }
  }
}

class Foo {

  public constructor(private thing: string) { }

  @someDecorator()
  bar() {
    console.log(this.thing);
  }
}

new Foo('Hello world!').bar();

Мне бы хотелось иметь вывод:

> Doing decorator stuff!
> Hello world!

, но, к сожалению, я получаю вывод:

> Doing decorator stuff!
> undefined

Кто-нибудь может указать мне правильное направление?

1 Ответ

2 голосов
/ 30 октября 2019

Полученное target будет прототипом класса, а не экземпляром. Таким образом, привязка метода к target приведет к потере контекста this фактического экземпляра и вызову его в контексте прототипа, который, как правило, не имеет ни одного из этих свойств экземпляра.

Вам нужно подождать, пока метод класса действительно будет вызван, чтобы получить соответствующий this. Поэтому забудьте target и вместо этого привяжите func к this в вашем новом методе. И обратите внимание, что функции стрелок не будут иметь своих собственных this, поэтому descriptor.value не должно быть функцией стрелки (без дополнительных прыжков с обручем). Поэтому я бы предложил вместо этого традиционный аноним function. Итак, измените реализацию someDecorator() на что-то вроде следующего:

function someDecorator() {
  return (target: any, _2: any, descriptor: PropertyDescriptor) => {
    const func = descriptor.value; // don't bind here
    descriptor.value = function (...args: any) {
      console.log('Doing decorator stuff!');
      func.apply(this, args); // bind here (applying args is optional I guess)
    }
  }
}

Это должно сработать сейчас:

new Foo('Hello world!').bar(); 
// Doing decorator stuff!
// Hello world!

Надеюсь, это поможет. Удачи!

Ссылка на код

...