В итоге я поиграл с декораторами и решил задокументировать то, что выяснил, для тех, кто хочет воспользоваться этим, до того, как появится какая-либо документация. Пожалуйста, не стесняйтесь редактировать это, если вы видите какие-либо ошибки.
Общие пункты
- Декораторы вызываются при объявлении класса, а не при создании экземпляра объекта.
- Несколько декораторов могут быть определены в одном классе / свойстве / методе / параметре.
- Декораторы не допускаются на конструкторы.
Действительный декоратор должен быть:
- Назначается одному из типов Decorator (
ClassDecorator | PropertyDecorator | MethodDecorator | ParameterDecorator
).
- Вернуть значение (в случае декораторов класса и метода декоратора), которое присваивается декорированному значению.
Ссылка
Метод / Формальный Accessor Decorator
Параметры реализации:
target
: Прототип класса ( Object
).
propertyKey
: Название метода ( string
| symbol
).
descriptor
: A TypedPropertyDescriptor
- Если вы не знакомы с ключами дескриптора, я рекомендовал бы читать об этом в этой документации на Object.defineProperty
(это третий параметр).
Пример - без аргументов
Использование:
class MyClass {
@log
myMethod(arg: string) {
return "Message -- " + arg;
}
}
Реализация:
function log(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) {
const originalMethod = descriptor.value; // save a reference to the original method
// NOTE: Do not use arrow syntax here. Use a function expression in
// order to use the correct value of `this` in this method (see notes below)
descriptor.value = function(...args: any[]) {
// pre
console.log("The method args are: " + JSON.stringify(args));
// run and store result
const result = originalMethod.apply(this, args);
// post
console.log("The return value is: " + result);
// return the result of the original method (or modify it before returning)
return result;
};
return descriptor;
}
Входные данные:
new MyClass().myMethod("testing");
Вывод:
Аргументы метода: ["testing"]
Возвращаемое значение: Сообщение - тестирование
Ноты:
- Не используйте синтаксис стрелки при установке значения дескриптора. Контекст
this
не будет экземпляром, если вы делаете.
- Лучше изменить исходный дескриптор, чем перезаписать текущий, возвращая новый дескриптор. Это позволяет вам использовать несколько декораторов, которые редактируют дескриптор без перезаписи того, что сделал другой декоратор. Это позволяет вам использовать что-то подобное
@enumerable(false)
и @log
одновременно (пример: плохо против хорошего )
- Полезно : Аргумент типа
TypedPropertyDescriptor
может использоваться для ограничения того, какие сигнатуры метода ( Пример метода ) или сигнатуры средства доступа ( Пример средства доступа ) можно использовать для декоратора.
Пример - с аргументами (фабрика декораторов)
При использовании аргументов вы должны объявить функцию с параметрами декоратора, а затем вернуть функцию с сигнатурой примера без аргументов.
class MyClass {
@enumerable(false)
get prop() {
return true;
}
}
function enumerable(isEnumerable: boolean) {
return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => {
descriptor.enumerable = isEnumerable;
return descriptor;
};
}
Статический метод Decorator
Похож на метод декоратор с некоторыми отличиями:
- Его
target
параметром является сама функция конструктора, а не прототип.
- Дескриптор определяется в функции конструктора, а не в прототипе.
Класс Декоратор
@isTestable
class MyClass {}
Параметр реализации:
target
: Класс декоратор объявлен на ( TFunction extends Function
).
Пример использования : использование метаданных api для хранения информации о классе.
Декоратор недвижимости
class MyClass {
@serialize
name: string;
}
Параметры реализации:
target
: Прототип класса ( Object
).
propertyKey
: Название объекта ( string
| symbol
).
Пример использования : создание @serialize("serializedName")
декоратора и добавление имени свойства в список свойств для сериализации.
Параметр Декоратор
class MyClass {
myMethod(@myDecorator myParameter: string) {}
}
Параметры реализации:
target
: Прототип класса ( Function
кажется, Function
он больше не работает. Вы должны использовать any
или Object
здесь, чтобы использовать декоратор в любом классе. Или указать тип (типы) класса, которым вы хотите его ограничить)
propertyKey
: Название метода ( string
| symbol
).
parameterIndex
: Индекс параметра в списке параметров функции ( number
).
Простой пример
Подробный пример (ы)
@Injectable
добавить в декоратор, обратитесь