Тепер пишіть чистіший і розумніший код

TypeScript — це строго типізована мова програмування, яка ґрунтується на JavaScript, надаючи вам кращі інструменти в масштабі. TypeScript було розроблено, щоб допомогти вирішити деякі проблеми, які виникають під час написання коду за допомогою JavaScript. TypeScript долає підводні камені JavaScript завдяки використанню типів.

Кожне значення у вихідному коді машинопису має тип. TypeScript перевіряє, чи кожне значення відповідає правилам, пов’язаним із його типом. TypeScript перевіряє наявність помилок у вашому вихідному коді без необхідності виконання або запуску програми.

Це називається статичною перевіркою типу, яка передбачає перевірку на наявність помилок у розробці на основі типу значень, що використовуються в програмі.

Окрім того, що TypeScript допомагає вам писати більш зрозумілий і читабельний код і забезпечує статичну перевірку типів, TypeScript пропонує додаткові функції, які допоможуть підвищити читабельність коду, можливість повторного використання та обслуговування. Однією з таких функцій є декоратори TypeScript.

Декоратори TypeScript

Декоратори в TypeScript — це функція, яка дозволяє змінювати або покращувати поведінку коду під час виконання або додавати метадані до коду. Декоратори дозволяють метапрограмувати в TypeScript. Метапрограмування — це техніка програмування, за якої програми можуть розглядати інші програми як свої дані й таким чином змінювати їх поведінку.

По суті, декоратори — це функції, які будуть викликані для виконання певної логіки під час виконання, коли здійснюється доступ до декорованих елементів або вони змінюються.

Таким чином можна додати декорованим елементам додаткову функціональність. Декоратори TypeScript можна приєднати до оголошень класів, методів, властивостей, засобів доступу (гетерів і сеттерів) і параметрів методів.

У TypeScript декоратори мають префікс символу @ і мають форму @expression з виразом, який обчислюється для функції, яка викликається під час виконання. Загальний синтаксис використання декораторів у TypeScript наведено нижче:

@decoratorName
itemToDecorate

Приклад простого декоратора класу показано нижче:

function logClass(target: Function) {
  console.log("The Log Class Decorator has been called")
  console.log("Class:", target);
}

@logClass // @logClass is a decorator
class MyClass {
  constructor() {
    console.log("An instance of MyClass has been created");
  }
}

const myInstance = new MyClass();

Результат виконання наведеного вище коду показано нижче:

Вихід:

The Log Class Decorator has been called
Class: [class MyClass]
An instance of MyClass has been created

Функція logClass() приймає один аргумент під назвою target типу Function. Цільовий аргумент має тип Function, оскільки він отримає конструктор класу, який ми декоруємо.

Щоб використовувати logClass() як декоратор для оформлення класу під назвою MyClass, ми розміщуємо @logclass безпосередньо перед оголошенням MyClass. Декоратор повинен мати те саме ім’я, що й функція, яку ви хочете використовувати для декорування елемента.

Коли екземпляр MyClass створюється, поведінка декоратора виконується на додаток до конструктора класу, як показано у виводі.

Наразі декоратори доступні на Typescript як експериментальна функція. Тому, щоб ви могли використовувати декоратори у TypeScript, вам потрібно ввімкнути експериментальні декоратори в опції компілятора у файлі tsconfig.json.

Для цього згенеруйте файл tsconfig.json у папці вашого проекту TypeScript, виконавши таку команду в терміналі, відкритому в каталозі вашого проекту:

tsc --init

Отримавши файл tsconfig.json, відкрийте його та розкоментуйте experimentalDecorators, як показано нижче:

Крім того, установіть цільову версію JavaScript принаймні ES2015.

Важливість декораторів TypeScript

Хороший код можна легко визначити за тим, наскільки він читабельний, придатний для повторного використання та обслуговування. Читабельний код — це код, який легко зрозуміти й інтерпретувати та чітко передає намір розробника тому, хто читає код.

З іншого боку, багаторазовий код — це код, який дозволяє певним компонентам, таким як функції та класи, перепрофілювати, адаптувати та використовувати в інших частинах програми або абсолютно новій програмі без істотних змін.

Підтримуваний код — це код, який можна легко змінювати, оновлювати та виправляти протягом усього терміну служби.

Декоратори TypeScript дозволяють досягти читабельності коду, можливості повторного використання та обслуговування. По-перше, декоратори TypeScript дозволяють покращити поведінку вашого коду за допомогою декларативного синтаксису, який легше читати. Ви можете інкапсулювати логіку в декоратори та викликати їх, прикрашаючи різні елементи вашого коду там, де вам потрібна логіка.

Це робить ваш код легким для читання та розуміння того, що відбувається. Декоратори чітко передають наміри розробника.

Декоратори не є одноразовими елементами; вони багаторазові за своєю природою. Ви можете створити декоратор один раз і використовувати його кілька разів у кількох областях.

Тому ви можете визначати декоратори, імпортувати їх і використовувати будь-де у своїй базі коду, де ви хочете змінити поведінку свого коду. Це вигідно, оскільки дозволяє уникнути дублювання логіки у вашій базі коду, таким чином підвищуючи можливість повторного використання вашого коду.

Декоратори також надають вам велику гнучкість і модульність у вашому коді, дозволяючи розділяти різні функції на незалежні компоненти. Це, у поєднанні з тим фактом, що вони дозволяють писати код, який можна читати та повторно використовувати, означає, що декоратори TypeScript дозволять вам мати код, який легко підтримувати.

Типи декораторів TypeScript

Як зазначалося раніше, декоратори TypeScript можна приєднати до класів, властивостей класу, методів класу, засобів доступу до класу та параметрів методу класу. З елементів, які ми можемо декорувати, ми отримуємо різні типи декораторів TypeScript. До таких декораторів відносяться:

#1. Декоратор класу

Декоратор класу — це декоратор, який використовується для спостереження, зміни або заміни визначення класу. Його оголошують безпосередньо перед класом, який він прикрашає. Декоратор класу застосовується до конструктора класу, який він декорує. Під час виконання буде викликано декоратор класу з єдиним аргументом конструктора класу, який він декорує.

Нижче показано декоратор класу, який використовується для запобігання розширенню класу:

function frozen(target: Function) {
  Object.freeze(target);
  Object.freeze(target.prototype)
}

@frozen
class Vehicle {
  wheels: number = 4;
  constructor() {
    console.log("A vehicle has been created")
  }
}

class Car extends Vehicle {
  constructor() {
    super();
    console.log("A car has been created");
  }
}

console.log(Object.isFrozen(Vehicle));

Щоб запобігти розширенню класу, ми використовуємо функцію Object.freeze() і передаємо клас, який хочемо заморозити. Для додавання цієї функції до класу використовується декоратор. Ми можемо перевірити, чи клас Vehicle заморожено під час виконання, передавши клас у isFrozen(), вихід коду показано нижче:

true

#2. Декоратор майна

Декоратор властивості використовується для оформлення властивості класу, і він оголошується безпосередньо перед оформленням властивості. Декоратори властивостей можна використовувати для зміни або спостереження за визначенням властивості.

Під час виконання буде викликано декоратор, який приймає два аргументи. По-перше, або функція-конструктор класу, якщо член є статичним, або прототип класу, якщо він є членом екземпляра. Другим аргументом є ім’я члена, тобто властивості, яку ви декоруєте.

У TypeScript статичні члени мають перед собою ключове слово static. До статичних членів можна отримати доступ без створення екземпляра класу. Члени екземпляра не мають перед собою ключового слова static, і до них можна отримати доступ лише після того, як екземпляр класу було створено.

Нижче наведено приклад декоратора властивості:

function wheelsDecorator(target: any, propertyName: string) {
  console.log(propertyName.toUpperCase())
}

class Vehicle {
  @wheelsDecorator
  wheels: number = 4;
  constructor() {
    console.log("A vehicle has been created")
  }
}

Результат виконання коду показано нижче:

WHEELS

#3. Декоратор методу

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

Другим аргументом є ім’я члена і, нарешті, дескриптор властивості для цього елемента. Дескриптор властивості — це об’єкт, пов’язаний із властивостями об’єкта, і він надає інформацію про атрибути та поведінку властивості.

Декоратори методів стають у нагоді, коли ви хочете виконати певну дію до або після виклику методу. Ми також можемо використовувати їх для реєстрації інформації про викликаний метод. Це може бути корисно, якщо ви хочете повідомити користувача, що метод застарів; тобто він все ще доступний для використання, але не рекомендується використовувати його, оскільки пізніше він може бути видалений.

Приклад декоратора методу показано нижче:

const logDeprecated =(target: any, methodName: string, descriptor: PropertyDescriptor) => {
  console.log(`${methodName} has been deprecated`)
  console.log(descriptor);
}

class Vehicle {
  wheels: number = 4;
  constructor() {
    console.log("A vehicle has been created")
  }
  @logDeprecated
  reFuel(): void {
    console.log("Your vehicle is being refuelled");
  }
}

Вихід:

reFuel has been deprecated
{
  value: [Function: reFuel],
  writable: true,
  enumerable: false,
  configurable: true
}

#4. Декоратори аксесуарів

У TypeScript існує два типи методів доступу: get і set. Методи доступу використовуються для керування доступом до властивостей класу. Декоратори аксесорів використовуються для оформлення цих двох методів аксесорів, і вони оголошуються безпосередньо перед оголошенням аксесорів. Оскільки аксесори все ще є методами, декоратори аксесорів працюють так само, як декоратори методів.

Нижче наведено приклад декораторів доступу:

const logWheels =(target: any, accessorName: string, descriptor: PropertyDescriptor) => {
  console.log(`${accessorName} used to get the number of wheels`)
  console.log(descriptor);
}

class Vehicle {
  private wheels: number = 4;
  constructor() {
    console.log("A vehicle has been created")
  }
  @logWheels
  get numWheels(): number {
    return this.wheels;
  }
}

Вихід:

numWheels used to get the number of wheels
{
  get: [Function: get numWheels],
  set: undefined,
  enumerable: false,
  configurable: true
}

Що стосується декораторів доступу, важливо зазначити, що декоратори не можуть бути застосовані до кількох інструментів доступу get/set з однаковою назвою. Наприклад, у нашому прикладі коду вище, якщо ви створюєте сеттер під назвою set numWheels, ви не можете використовувати для нього декоратор logWheels.

#5. Декоратори параметрів

Декоратор параметрів використовується, щоб спостерігати, що параметр було оголошено в методі, і він оголошується перед оголошенням параметра. Декоратори параметрів приймають три аргументи, по-перше, функцію конструктора класу для статичного члена або прототип класу для члена екземпляра.

Другим аргументом є ім’я члена, тобто ім’я параметра. Третій аргумент — це порядковий індекс параметра в списку параметрів функції. Тобто, яку позицію займає параметр у списку параметрів, коли перший параметр має індекс 0?

Нижче наведено приклад декоратора параметрів:

const passengerLog = (target: Object, propertyKey: string, parameterIndex: number) => {
  console.log(`Decorator on ${propertyKey}'s paremeter index ${parameterIndex}`);
}

class Vehicle {
  private wheels: number = 4;
  constructor() {
    console.log("A vehicle has been created")
  }
  pickPassenger( location: string, numPassengers: string, @passengerLog driver: string) {
    console.log(`${numPassengers} picked at ${location} by ${driver}`)
  }
  dropPassenger(driver: string, @passengerLog location: string, numPassengers: string) {
    console.log(`${numPassengers} dropped at ${location} by ${driver}`)
  }
}

Вихід:

Decorator on pickPassenger's paremeter index 2
Decorator on dropPassenger's paremeter index 1

Висновок

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

Незважаючи на те, що вони все ще є експериментальною функцією, декоратори дуже корисні, і вам обов’язково слід ознайомитися з ними.

Ви також можете прочитати, як перетворити рядок на число в TypeScript.