В TypeScript, начиная с версии 1.5, появилась поддержка шаблона "декоратор". Давайте разберемся как и зачем его можно использовать.
В первую очередь вспомним для чего необходим указанный шаблон:
Декоратор предназначен для динамического добавления объекту новой функциональности. Является гибкой альтернативой механизму наследования, в том числе и множественного.
Идея шаблона заключена в следующем: Декоратор является оберткой над исходным компонентом. Он реализует тот же самый интерфейс, поэтому может замещать этот компонент. Однако, цель шаблона не просто в переадресации запросов. Он добавляет свой код до и/или после вызовов исходных методов, в крайнем случае замещая их полностью. Это приводит к изменению исходного поведения и появлению новых возможностей.
Из статьи "Структурные шаблоны: Декоратор (Decorator)"
Проще говоря, разработчик, используя декоратор, может изменять поведение объекта не модифицируя и не наследуя сам объект. Подробное описание шаблона, а так же примеры на языке C#, можно найти в указанной выше статье.
Декоратор в TypeScript это обычная функция, объявленная следующим образом:
function decoratorName(target: Function, key: string, value: any) {
return {
value: (...args: any[]) => {
// Код выполняемый до вызова декорируемого метода
// Вызов исходного метода
var result = value.value.apply(this, args);
// Код выполняемый после вызова декорируемого метода
return result;
}
};
}
В качестве параметров передаются:
- target – прототип класса, в котором установлен данный декоратор;
- key – имя метода (функции, свойства) на котором установлен декоратор;
- value – дескриптор метода (функции, свойства), на который установлен декоратор. Сам метод можно получить обратившись к value.vaule.
Функция декоратора должна вернуть новый дескриптор. В его свойстве value располагается код, который будет вызываться при обращениях к декорируемому методу, параметры которого так же будут переданы в виде массива args.
Чтобы установить декоратор используется следующий синтаксис:
class SomeClass {
@decoratorName
SomeMethod(…) { … }
}
В качестве примера, создадим декоратор, который выводит на консоль браузера сообщения о вызовах декорируемого метода со списком его параметров и значением результата:
function logCall(target: Function, key: string, value: any) {
return {
value: (...args: any[]) => {
// создаем строку значениями параметров
var a = args.map(a => JSON.stringify(a)).join();
// вызываем декорируемый метод
var result = value.value.apply(this, args);
// создаем строку с результатом работы метода
var r = JSON.stringify(result);
// выводим на консоль строку с вызовом функции
console.log("Вызов: ${key}(${a}) > ${r}");
// возвращаем результат
return result;
}
};
}
class DecoratorDemo {
@logCall
Add(n1: number, n2: number): number {
return n1 + n2;
}
}