TypeScript - Декораторы
Здравствуйте, ambitные программисты! Сегодня мы отправимся в увлекательное путешествие в мир декораторов TypeScript. Не волнуйтесь, если вы новички в программировании - я буду вести вас шаг за шагом через это понятие, как я делал это для countless студентов на протяжении многих лет моей преподавательской деятельности. Итак, погружаемся!
Что такое декораторы?
Прежде чем углубиться в детали, давайте поймем, что такое декораторы. Представьте себе обычный кекс. Декораторы resemble посыпку, глазурь и вишенку на вершине, которые делают ваш кекс extra special. В TypeScript декораторы добавляют extra функциональность вашим классам, методам, свойствам и параметрам.
Использование декораторов в TypeScript
Чтобы начать использовать декораторы в TypeScript, вам нужно включить их в вашем файле tsconfig.json
. Это как включение духовки перед выпечкой ваших кексов!
{
"compilerOptions": {
"experimentalDecorators": true
}
}
Синтаксис декораторов
Теперь давайте посмотрим, как мы пишем декораторы. Это проще, чем вы можете подумать!
function simpleDecorator(target: any) {
console.log("Я простой декоратор!");
}
@simpleDecorator
class MyClass {
// Реализация класса
}
В этом примере simpleDecorator
resembles наклейку, которую мы клеим на наш MyClass
. Каждый раз, когда мы используем MyClass
, он будет выводить "Я простой декоратор!" в консоль.
Фабрики декораторов
Иногда мы хотим, чтобы наши декораторы были настраиваемыми. Вот где появляются фабрики декораторов. Они resemble machine, которая производит декораторы на основе ваших спецификаций.
function decoratorFactory(message: string) {
return function (target: any) {
console.log(message);
}
}
@decoratorFactory("Привет, я пользовательский декоратор!")
class MyClass {
// Реализация класса
}
Здесь decoratorFactory
создает декоратор, который выводит ваше пользовательское сообщение.
Композиция декораторов
Мы можем использовать несколько декораторов для одной цели. Это resembles добавление нескольких начинок к вашему кексу!
function first() {
console.log("first(): фабрика оценена");
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("first(): вызван");
};
}
function second() {
console.log("second(): фабрика оценена");
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("second(): вызван");
};
}
class ExampleClass {
@first()
@second()
method() {}
}
В этом случае декораторы применяются снизу вверх: second()
затем first()
.
Почему использовать декораторы?
Декораторы incredibly полезны для:
- Добавления метаданных к вашему коду
- Изменения поведения классов и методов
- Реализации аспектов Aspect-Oriented Programming
- Создания повторно используемого кода, который можно легко применить к нескольким классам
Декораторы классов
Декораторы классов применяются к конструктору класса и могут использоваться для наблюдения, изменения или замены определения класса.
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
В этом примере декоратор @sealed
предотвращает изменение класса Greeter
после его определения.
Методы декораторов
Методы декораторов могут использоваться для изменения, наблюдения или замены определения метода.
function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@enumerable(false)
greet() {
return "Hello, " + this.greeting;
}
}
Здесь декоратор @enumerable(false)
делает метод greet
неудаляемым.
Декораторы доступа
Декораторы доступа применяются к дескриптору свойства для доступа и могут использоваться для наблюдения, изменения или замены определений доступа.
function configurable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.configurable = value;
};
}
class Point {
private _x: number;
private _y: number;
constructor(x: number, y: number) {
this._x = x;
this._y = y;
}
@configurable(false)
get x() { return this._x; }
@configurable(false)
get y() { return this._y; }
}
В этом примере декоратор @configurable(false)
делает доступы x
и y
неудаляемыми.
Декораторы свойств
Декораторы свойств используются для наблюдения, изменения или замены определения свойства.
function format(formatString: string) {
return function (target: any, propertyKey: string): any {
let value = target[propertyKey];
const getter = function () {
return `${formatString} ${value}`;
};
const setter = function (newVal: string) {
value = newVal;
};
return {
get: getter,
set: setter,
enumerable: true,
configurable: true
};
};
}
class Greeter {
@format("Hello,")
greeting: string;
}
const greeter = new Greeter();
greeter.greeting = "World";
console.log(greeter.greeting); // Выводит: "Hello, World"
Здесь декоратор @format
добавляет префикс к свойству greeting
.
Декораторы параметров
Декораторы параметров используются для наблюдения, изменения или замены определения параметра.
function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {
let existingRequiredParameters: number[] = Reflect.getOwnMetadata("required", target, propertyKey) || [];
existingRequiredParameters.push(parameterIndex);
Reflect.defineMetadata("required", existingRequiredParameters, target, propertyKey);
}
class Greeter {
greet(@required name: string) {
return "Hello " + name;
}
}
В этом примере декоратор @required
помечает параметр name
как обязательный.
Методы декораторов
Вот таблица, резюмирующая различные типы декораторов и их методы:
Тип декоратора | Метод |
---|---|
Декоратор класса | declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void; |
Декоратор метода | declare type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void; |
Декоратор доступа | declare type AccessorDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void; |
Декоратор свойства | declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void; |
Декоратор параметра | declare type ParameterDecorator = (target: Object, propertyKey: string | symbol, parameterIndex: number) => void; |
И вот мы covered основы декораторов TypeScript. Помните, как обучение выпекать идеальный кекс, овладение декораторами требует практики. Не бойтесь экспериментировать и делать ошибки - это как мы учимся и растем как программисты. Счастливого кодирования!
Credits: Image by storyset