Декораторы в TypeScript

Для чего используется TypeScript Изучение

Декораторы почти всегда были частью ECMAScript, сколько я себя помню. Эти изящные инструменты позволяют нам изменять классы и члены с возможностью повторного использования. Они уже некоторое время присутствуют на TypeScript, хотя и под экспериментальным флагом. Хотя итерация декораторов Стадии 2 всегда была экспериментальной, декораторы широко использовались в таких библиотеках, как MobX, Angular, Nest и TypeORM. Декораторы TypeScript 5.0 полностью синхронизированы с предложением ECMAScript, которое практически готово к прайм-тайму и находится на этапе 3.

Декораторы позволяют нам создать функцию, которая настраивает поведение класса и его методов. Представьте, что вам нужно внедрить в наши методы некоторые операторы отладки. До TypeScript 5.0 нам приходилось вручную копировать и вставлять операторы отладки в каждый метод. С декораторами мы просто выполняем работу один раз, и изменения будут поддерживаться каждым методом, к которому прикреплен декоратор.

Допустим, мы хотим создать декоратор для регистрации того, что данный метод устарел:

class Card {
  constructor(public suit: Suit, public rank: Rank) {
    this.suit = suit;
    this.rank = rank;
  }

  get name(): CardName {
    return `${this.rank} of ${this.suit}`;
  }

  @deprecated // 👀 This is a decorator!
  getValue(): number {
    if (this.rank === 'Ace') return 14;
    if (this.rank === 'King') return 13;
    if (this.rank === 'Queen') return 12;
    if (this.rank === 'Jack') return 11;
    return this.rank;
  }

  // The new way to do it!
  get value(): number {
    if (this.rank === 'Ace') return 14;
    if (this.rank === 'King') return 13;
    if (this.rank === 'Queen') return 12;
    if (this.rank === 'Jack') return 11;
    return this.rank;
  }
}

const card = new Card('Spades', 'Queen');
card.getValue();

card.getValue() Мы хотим, чтобы при каждом вызове на консоль записывалось предупреждающее сообщение. Мы могли бы реализовать вышеуказанный декоратор следующим образом:

const deprecated = <This, Arguments extends any[], ReturnValue>(
  target: (this: This, ...args: Arguments) => ReturnValue,
  context: ClassMethodDecoratorContext<
    This,
    (this: This, ...args: Arguments) => ReturnValue
  >,
) => {
  const methodName = String(context.name);

  function replacementMethod(this: This, ...args: Arguments): ReturnValue {
    console.warn(`Warning: '${methodName}' is deprecated.`);
    return target.call(this, ...args);
  }

  return replacementMethod;
};

На первый взгляд это может показаться немного запутанным, но давайте разберемся:

  • Наша функция-декоратор принимает два аргумента: targetи context.
  • targetэто сам метод, который мы украшаем.
  • contextметаданные о методе.
  • Мы возвращаем некоторый метод, имеющий ту же сигнатуру.
  • В этом случае мы вызываем console.warnзапись уведомления об устаревании, а затем вызываем метод.
Читайте также:  Как прогнозировать акции с помощью SVM?

Тип ClassMethodDecoratorимеет следующие свойства:

  • kind: тип декорируемого свойства. В приведенном выше примере это будет method, поскольку мы украшаем метод экземпляра Card.
  • name: имя свойства. В приведенном выше примере это getValue.
  • static: значение, указывающее, является ли элемент класса статическим ( true) или falseэлементом экземпляра ( ).
  • private: значение, указывающее, имеет ли элемент класса частное имя.
  • access: объект, который можно использовать для доступа к текущему значению элемента класса во время выполнения.
  • has: определяет, имеет ли объект свойство с тем же именем, что и у декорированного элемента.
  • get: вызывает установщик для предоставленного объекта.

Декораторы предоставляют удобный синтаксический сахар для добавления сообщений журнала, как мы это сделали в примере выше, а также для ряда других распространенных случаев использования. Например, мы могли бы создать декоратор, который автоматически привязывает метод к текущему экземпляру или изменяет дескриптор свойства метода или класса.

Оцените статью
bestprogrammer.ru
Добавить комментарий