«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Понимание декораторов в TypeScript: подход из первых принципов

Понимание декораторов в TypeScript: подход из первых принципов

Опубликовано 1 ноября 2024 г.
Просматривать:239

Understanding Decorators in TypeScript: A First-Principles Approach

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

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

Что такое Декоратор?

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

Давайте начнем с простого примера декоратора метода, который регистрирует вызов метода:

function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`Calling ${propertyKey} with arguments: ${args}`);
    return originalMethod.apply(this, args);
  };

  return descriptor;
}

class Example {
  @log
  greet(name: string) {
    return `Hello, ${name}`;
  }
}

const example = new Example();
example.greet('John');

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

Как работают декораторы

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

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

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

  • Декораторы классов : функция, получающая конструктор класса.
function classDecorator(constructor: Function) {
  // Modify or extend the class constructor or prototype
}
  • Декораторы метода: функция, которая получает целевой объект, имя метода и дескриптор метода.
function methodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  // Modify the method's descriptor
}
  • Декораторы свойств: функция, которая получает целевой объект и имя свойства.
function propertyDecorator(target: any, propertyKey: string) {
  // Modify the behavior of the property
}
  • Декораторы параметров : функция, которая получает цель, имя метода и индекс параметра.
function parameterDecorator(target: any, propertyKey: string, parameterIndex: number) {
  // Modify or inspect the method's parameter
}

Передача аргументов декораторам

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

function logConditionally(shouldLog: boolean) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = function (...args: any[]) {
      if (shouldLog) {
        console.log(`Calling ${propertyKey} with arguments: ${args}`);
      }
      return originalMethod.apply(this, args);
    };

    return descriptor;
  };
}

class Example {
  @logConditionally(true)
  greet(name: string) {
    return `Hello, ${name}`;
  }
}

const example = new Example();
example.greet('TypeScript Developer');

Передавая true декоратору logConditionally, мы гарантируем, что метод протоколирует свое выполнение. Если мы передаем false, ведение журнала пропускается. Эта гибкость является ключом к тому, чтобы сделать декораторы универсальными и многоразовыми.

Реальные применения декораторов

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

  • Проверка в class-validator: В приложениях, управляемых данными, проверка имеет решающее значение. Пакет class-validator использует декораторы для упрощения процесса проверки полей в классах TypeScript.
import { IsEmail, IsNotEmpty } from 'class-validator';

class User {
  @IsNotEmpty()
  name: string;

  @IsEmail()
  email: string;
}

В этом примере декораторы @IsEmail и @IsNotEmpty гарантируют, что поле электронной почты является действительным адресом электронной почты, а поле имени не пусто. Эти декораторы экономят время, устраняя необходимость в логике ручной проверки.

  • Объектно-реляционное сопоставление с помощью TypeORM: Декораторы широко используются в средах ORM, таких как TypeORM, для сопоставления классов TypeScript с таблицами базы данных. Это сопоставление выполняется декларативно с помощью декораторов.
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column()
  email: string;
}

Здесь @Entity, @Column и @PrimaryGeneratedColumn определяют структуру таблицы User. Эти декораторы абстрагируют сложность создания таблиц SQL, делая код более читабельным и удобным в обслуживании.

  • Внедрение зависимостей Angular: В Angular декораторы играют ключевую роль в управлении сервисами и компонентами. Декоратор @Injectable помечает класс как сервис, который можно внедрить в другие компоненты или сервисы.
@Injectable({
  providedIn: 'root',
})
class UserService {
  constructor(private http: HttpClient) {}
}

В этом случае декоратор @Injectable сигнализирует системе внедрения зависимостей Angular, что UserService должен быть предоставлен глобально. Это обеспечивает плавную интеграцию сервисов в приложении.

Реализация собственных декораторов: анализ

Декораторы по своей сути — это просто функции. Давайте разберем процесс создания декораторов с нуля:

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

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

function AddTimestamp(constructor: Function) {
  constructor.prototype.timestamp = new Date();
}

@AddTimestamp
class MyClass {
  id: number;
  constructor(id: number) {
    this.id = id;
  }
}

const instance = new MyClass(1);
console.log(instance.timestamp);  // Outputs the current timestamp

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

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

function logExecutionTime(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    const start = performance.now();
    const result = originalMethod.apply(this, args);
    const end = performance.now();
    console.log(`${propertyKey} executed in ${end - start}ms`);
    return result;
  };

  return descriptor;
}

class Service {
  @logExecutionTime
  execute() {
    // Simulate work
    for (let i = 0; i 



Декоратор недвижимости

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

function trackChanges(target: any, propertyKey: string) {
  let value = target[propertyKey];

  const getter = () => value;
  const setter = (newValue: any) => {
    console.log(`${propertyKey} changed from ${value} to ${newValue}`);
    value = newValue;
  };

  Object.defineProperty(target, propertyKey, {
    get: getter,
    set: setter,
  });
}

class Product {
  @trackChanges
  price: number;

  constructor(price: number) {
    this.price = price;
  }
}

const product = new Product(100);
product.price = 200;  // Logs the change

Заключение

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

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

Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/curious_tinkerer/understanding-decorators-in-typescript-a-first-principles-approach-2n3h?1 Если есть какие-либо нарушения, пожалуйста, свяжитесь с [email protected], чтобы удалить это
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3