TYPESCRIPT19 октября

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

Декоратор в TypeScript — это функция, которая может применяться к классу, методу, свойству или параметру для изменения их поведения или добавления новых данных, свойств или методов. Декоратор предоставляет возможность модифицировать исходный элемент, к которому он применяется, без изменения его внутренней логики. Декоратор всегда реализуется как функция, хотя он может внутри использовать логику работы с классами, если это необходимо.

Представим, что декоратор в TypeScript работает как некий "контроллер" или "фильтр", который добавляет или изменяет поведение обычных объектов, методов или свойств.

Давайте рассмотрим это на житейском примере:

Пример из реальной жизни: Декоратор как шеф-повар

  1. Исходная ситуация (без декоратора): Ты заказываешь пиццу в пиццерии. Пицца готовится по стандартному рецепту: тесто, соус, сыр, и готово.

  2. Применение декоратора (декорированная ситуация): Представь, что шеф-повар решает улучшить пиццу с помощью "секретного ингредиента". Это его собственный фирменный штрих — например, он добавляет свежие травы или особенный соус.

    Вот как это выглядит:

    • Пицца по-прежнему остается пиццей — основа не меняется, это всё ещё тесто, соус, сыр.
    • Шеф-повар применяет свой "декоратор" — добавляет свежие травы и особенный соус.
    • В результате получается та же пицца, но улучшенная и с дополнительными вкусами.
  3. Применение декоратора в мире программирования:

    • Без декоратора: Метод класса работает по стандартному сценарию, например, просто складывает два числа.
    • С декоратором: Ты добавляешь декоратор, который, например, логирует вызов метода или делает проверку аргументов, но сам метод продолжает работать как обычно (например, складывает числа). Декоратор лишь добавляет дополнительные действия до или после выполнения основной функции.

Сравнение:

  • Пицца = метод в классе — основное действие не изменяется.
  • Шеф-повар = декоратор — добавляет дополнительное действие (например, добавляет логирование, проверку или новый соус), но не меняет саму суть (пицца остаётся пиццей, а метод выполняет свою работу).

Вывод:

Декоратор не изменяет саму "пиццу" (метод, класс и т.д.), но может добавить дополнительные действия — как шеф-повар, который украшает уже готовое блюдо, чтобы оно было более интересным и функциональным.

Таким образом Декоратор в TypeScript — это функция, которая применяется к классу, методу, свойству или параметру и изменяет их поведение или добавляет новые данные, свойства или методы. Его задача — влиять на элементы, к которым он применен, за счет возможности доступа к их метаданным и модификации их поведения. Важно, что декораторы не обязательно добавляют новые свойства или методы, они могут также просто изменять существующие или выполнять побочные эффекты (например, логирование).

В TypeScript декоратор всегда реализован как функция. Хотя внутри этой функции можно создавать экземпляры классов или выполнять другие действия, декораторы не реализуются непосредственно как классы. Класс может быть частью логики внутри декоратора, но сам декоратор — это всегда функция.

Логика декоратора в TypeScript заключается в том, что это специальная функция, которая получает доступ к элементам (классу, методу, свойству или параметру) и может изменить их поведение, добавляя новые свойства, методы, или изменяя существующие.

Как это работает:

  1. Применение декоратора: Декоратор аннотируется с помощью символа @ перед элементом, к которому применяется. Когда TypeScript компилирует код, декоратор получает доступ к метаданным этого элемента.

  2. Функция декоратора: Декоратор — это функция, которая принимает один или несколько аргументов, в зависимости от типа элемента (класс, метод, свойство и т.д.). Эти аргументы позволяют декоратору взаимодействовать с целевым элементом.

    • Для класса: декоратор получает конструктор класса.
    • Для метода: декоратор получает метод и его метаданные.
    • Для свойства: декоратор получает информацию о свойстве.
    • Для параметра: декоратор получает индекс параметра и его метаданные.
  3. Изменение поведения: Декоратор может изменить исходное поведение элемента несколькими способами:

    • Добавить новые свойства или методы.
    • Изменить существующие методы (например, обернуть метод в дополнительную логику).
    • Изменить значения или логику, которая связана с элементом.
    • Выполнить побочные действия, такие как логирование или валидация.
  4. Возврат измененного элемента: Декоратор может либо вернуть неизмененный элемент (например, класс), либо вернуть модифицированный элемент (например, изменить метод или конструктор).

Шаги выполнения:

  1. Применение: Когда компилятор видит @decorator, он вызывает соответствующую функцию-декоратор.
  2. Получение аргументов: Декоратору передаются метаданные элемента, который он декорирует.
  3. Модификация: Декоратор может модифицировать элемент, добавлять новую логику или сохранять метаданные.
  4. Возврат: Функция декоратора может вернуть либо изменённый элемент, либо тот же самый, если изменения не нужны.

Пример логики для метода:

function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
 
  descriptor.value = function(...args: any[]) {
    console.log(`Вызов метода ${propertyKey} с аргументами: ${args}`);
    const result = originalMethod.apply(this, args);
    console.log(`Результат: ${result}`);
    return result;
  };
}
 
class Calculator {
  @log
  add(a: number, b: number) {
    return a + b;
  }
}
 
const calc = new Calculator();
calc.add(2, 3); 

Логика этого декоратора:

  • Применение: Декоратор @log применяется к методу add.
  • Получение метаданных: Функция декоратора получает три параметра:
    • target: Класс, в котором находится метод.
    • propertyKey: Имя метода add.
    • descriptor: Описание метода, которое содержит исходную функцию.
  • Модификация метода: Декоратор изменяет метод, добавляя логирование перед и после вызова исходной функции.
  • Результат: Теперь каждый раз, когда метод add вызывается, будет выводиться информация об аргументах и результате.

Итоговая логика:

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

Cимвол @ в TypeScript обозначает декоратор.

Когда вы видите @, это указывает на использование декоратора для класса, метода, свойства или параметра. Этот символ вводит дополнительную функциональность, например, аннотацию или модификацию поведения объекта.

Пример: typescript

function logClass(constructor: Function) {
  console.log(`Создание экземпляра класса: ${constructor.name}`);
}
 
@logClass
class MyClass {
  constructor() {
    console.log('Конструктор MyClass вызван');
  }
}
 
const instance = new MyClass();
// Лог:
// Создание экземпляра класса: MyClass
// Конструктор MyClass вызван

Здесь:

  • @logClass — это декоратор класса. Он применяется к классу MyClass и добавляет дополнительную логику.

Декораторы являются частью стандартного синтаксиса TypeScript и используются для добавления метаданных и изменения функциональности классов и их элементов.

В фреймворке Angular декораторы также активно применяются для аннотации компонентов, сервисов и других элементов. Например, декоратор @Component используется для описания метаданных Angular-компонента.

Декораторы в TypeScript — это специальный вид объявления, который позволяет аннотировать и модифицировать классы и их члены (методы, свойства и параметры). Декораторы работают на уровне классов, а не на уровне экземпляров объектов, и служат для того, чтобы добавлять дополнительные функциональные возможности или менять поведение классов или их частей.

Виды декораторов:

  1. Декоратор класса — применяется к самому классу.
  2. Декоратор метода — применяется к методу класса.
  3. Декоратор свойства — применяется к свойству класса.
  4. Декоратор параметра — применяется к параметру метода.

Как включить декораторы

Для того чтобы использовать декораторы, необходимо включить их поддержку в конфигурации TypeScript (tsconfig.json):

{
"compilerOptions": {
"experimentalDecorators": true
}
}

Декоратор класса

Декоратор класса используется для изменения поведения самого класса.

Пример:

function sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}
 
@sealed
class Person {
  constructor(public name: string) {}
}
 
let p = new Person('John');
console.log(p);  // Person { name: 'John' }

В этом примере декоратор @sealed "запечатывает" класс, предотвращая добавление новых свойств и методов в класс или его прототип.

Что делает @sealed?

Когда класс аннотируется декоратором @sealed, следующие действия происходят:

  1. Object.seal(constructor): Этот метод предотвращает добавление новых статических свойств или методов в класс Person. Существующие свойства и методы остаются изменяемыми, но добавлять новые нельзя.

  2. Object.seal(constructor.prototype): Этот вызов предотвращает добавление новых методов или свойств к прототипу класса, тем самым ограничивая расширение экземпляров класса. Экземпляры класса больше не могут получать новые методы или свойства через прототип.

Таким образом, этот декоратор "запечатывает" как сам класс, так и его прототип, предотвращая дальнейшие изменения.

Более сложный пример с использованием декоратора

 
Декораторы классов можно использовать для выполнения более сложных действий, например, добавления новых свойств или методов, логирования создания объектов, проверки условий или контроля доступа.
 
Пример 2: Декоратор, добавляющий статическое свойство к классу
 
function addTimestamp(constructor: Function) {
  constructor.prototype.timestamp = new Date();
}
 
@addTimestamp
class User {
  constructor(public name: string) {}
}
 
const user = new User('Alice');
console.log(user.timestamp); // Выведет текущую дату и время
 
В этом примере декоратор addTimestamp добавляет свойство timestamp ко всем экземплярам класса User, устанавливая в него текущую дату и время при создании объекта.
 
Пример 3: Логирование действий класса через декоратор
Декораторы классов также могут быть полезны для логирования или отслеживания создания объектов, вызова методов и других действий.
 
function logCreation(constructor: Function) {
  const originalConstructor = constructor;
 
  function newConstructor(...args: any[]) {
    console.log(`Создание экземпляра класса: ${originalConstructor.name}`);
    return new originalConstructor(...args);
  }
 
  newConstructor.prototype = originalConstructor.prototype;
  return newConstructor;
}
 
@logCreation
class Car {
  constructor(public brand: string) {}
}
 
const myCar = new Car('Tesla');
// Лог:
// Создание экземпляра класса: Car
 
Здесь декоратор logCreation заменяет конструктор класса новой функцией, которая перед созданием экземпляра записывает в лог сообщение. Это может быть полезно для отслеживания активности в приложении.
 
Пример: Валидация аргументов
 
Также декоратор может использоваться для валидации аргументов, передаваемых в конструктор.
 
function validate(constructor: Function) {
  return class extends constructor {
    constructor(...args: any[]) {
      if (args.length === 0) {
        throw new Error('Нельзя создать объект без имени!');
      }
      super(...args);
    }
  };
}
 
@validate
class Product {
  constructor(public name: string) {}
}
 
try {
  const product = new Product('');
} catch (error) {
  console.error(error.message); // Нельзя создать объект без имени!
}
 
Декоратор validate изменяет конструктор класса Product, чтобы выбрасывать ошибку, если в конструктор переданы некорректные аргументы.
Важные моменты:
Неизменяемость структуры класса: Декоратор @sealed предотвращает дальнейшие изменения структуры класса, что может быть полезно для создания строгих классов, где важна предсказуемость структуры и поведения.
 
Возможности расширения: Декораторы классов позволяют расширять функциональность классов, добавляя к ним дополнительные свойства или методы без изменения исходного кода класса.
 
Контроль над созданием объектов: С помощью декораторов можно контролировать процесс создания объектов класса, добавлять логику валидации или логирования.
 
Совместимость с Angular: В Angular декораторы используются для аннотирования компонентов, сервисов и других элементов, добавляя метаданные и инструкции для фреймворка. Это пример того, как мощные возможности декораторов используются в реальных приложениях.
 
Итог:
Декораторы классов — это мощный инструмент в TypeScript, позволяющий модифицировать или добавлять функциональность к классам.

Декоратор метода

Этот декоратор применяется к методам класса и позволяет изменять или аннотировать поведение метода.

Пример: typescript

function log(target: Object, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`Вызов метода ${propertyKey} с аргументами: ${args}`);
    return originalMethod.apply(this, args);
  };
  return descriptor;
}
 
class Calculator {
  @log
  add(a: number, b: number): number {
    return a + b;
  }
}
 
let calc = new Calculator();
console.log(calc.add(2, 3));  // Лог вызова и результат: 5

В этом примере декоратор @log оборачивает метод add, чтобы логировать его вызовы.

Декоратор свойства

Декоратор свойства позволяет изменять или аннотировать свойство класса.

Пример:

function readonly(target: any, propertyKey: string) {
  Object.defineProperty(target, propertyKey, {
    writable: false
  });
}
 
class Cat {
  @readonly
  name: string = 'Tom';
}
 
let cat = new Cat();
cat.name = 'Jerry';  // Ошибка: name является только для чтения

Здесь декоратор @readonly делает свойство name доступным только для чтения.

Декоратор параметра

Этот декоратор применяется к параметрам методов и позволяет добавлять метаданные для параметра.

Пример:

function logParameter(target: Object, propertyKey: string, parameterIndex: number) {
  console.log(`Параметр в методе ${propertyKey} на позиции ${parameterIndex}`);
}
 
class Car {
  start(@logParameter speed: number): void {
    console.log(`Машина едет со скоростью ${speed}`);
  }
}
 
let car = new Car();
car.start(100);  // Лог: Параметр в методе start на позиции 0

Использование декораторов в Angular

В Angular декораторы широко используются для аннотации компонентов, сервисов и других сущностей.

Пример декоратора компонента в Angular:

import { Component } from '@angular/core';
 
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'My Angular App';

В данном примере декоратор @Component используется для создания Angular компонента, указывая метаданные для его селектора, шаблона и стилей.

Итог:

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

Декораторы а Angular

Теги: #typescript

Комментарии

Добавить комментарий:

Отметьте что вы не робот

Вернуться наверх