У меня проблема с декораторами методов и декораторами классов - PullRequest
1 голос
/ 21 апреля 2019

У меня есть декоратор класса, и этот декоратор класса меняет класс и добавляет в него свойство. Затем у меня есть декоратор метода, который находится внутри класса с этим декоратором класса, и декоратор метода пытается получить доступ к свойству в классе, созданном другим декоратором.

// The Class Decorator
export function SomeDecorator(): ClassDecorator {
  return target => {
    target['property'] = { text: 'some text' };

    return target;
  }
}

// The Method Decorator
export function SomeOtherDecorator(): MethodDecorator {
  return (target, propertyKey: string, propertyDescriptor: PropertyDescriptor) => {
    console.log(target['property'].text);
  }
}

// The Class
@SomeDecorator()
export class SomeClass {
  @SomeOtherDecorator()
  someMethod() {}
}

Это ответит во время выполнения: Ошибка типа: не удается прочитать свойство 'text' из неопределенного

Почему?

1 Ответ

0 голосов
/ 21 апреля 2019

Как сказал Тициан, декораторы классов запускаются после декораторов методов, поэтому ваш пример кода console.log(target['property'].text); терпит неудачу.

Не уверен насчет вашего фактического варианта использования, но если вы можете отложить доступ к target['property'], у вас не возникнет никаких проблем.

function SomeOtherDecorator(): MethodDecorator {
  return (target, propertyKey: string, propertyDescriptor: PropertyDescriptor) => {
    const fn = descriptor.value;
    // no problem, because `target['property']` is only accessed
    // when the decorated method (not decorator) is called.
    descriptor.value = (...args) => {
      console.log(target['property'].text);
      return fn.apply(target, args);
    };
  }
}

Вы даже можете использовать getter для своего рода ленивого запуска декоратора, следует позаботиться о большинстве случаев использования.

function SomeOtherDecorator(): MethodDecorator {
  return (target, propertyKey: string, propertyDescriptor: PropertyDescriptor) => {
    const fn = descriptor.value;
    let decoratedFn;
    descriptor.get = () => {
      if (decoratedFn) return decoratedFn;
      // do whatever you want to decorate the method/fn
      // including access to `target['property']`
      decoratedFn = ...
    }
...