W końcu bawiłem się z dekoratorami i postanowiłem udokumentować to, co wymyśliłem dla każdego, kto chce skorzystać z tego, zanim pojawi się jakakolwiek dokumentacja. Jeśli zauważysz jakieś błędy, edytuj to.
Punkty ogólne
- Dekoratory są wywoływane, gdy klasa jest zadeklarowana, a nie podczas tworzenia obiektu.
- W tej samej klasie / właściwości / metodzie / parametrze można zdefiniować wiele dekoratorów.
- Dekoratorzy nie są dozwoleni na konstruktorach.
Prawidłowym dekoratorem powinien być:
- Można przypisać do jednego z typów Dekoratora (
ClassDecorator | PropertyDecorator | MethodDecorator | ParameterDecorator
).
- Zwraca wartość (w przypadku dekoratorów klas i dekoratorów metod), którą można przypisać do dekorowanej wartości.
Odniesienie
Method / Formal Accessor Decorator
Parametry realizacji:
target
: Prototyp klasy ( Object
).
propertyKey
: Nazwa metody ( string
| symbol
).
descriptor
: A TypedPropertyDescriptor
- Jeśli nie znasz kluczy deskryptora, polecam przeczytać o tym w tej dokumentacji na Object.defineProperty
(jest to trzeci parametr).
Przykład - bez argumentów
Posługiwać się:
class MyClass {
@log
myMethod(arg: string) {
return "Message -- " + arg;
}
}
Realizacja:
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;
}
Wejście:
new MyClass().myMethod("testing");
Wynik:
Argumenty metody to: [„testowanie”]
Zwracana wartość to: Wiadomość - testowanie
Uwagi:
- Nie używaj składni strzałek podczas ustawiania wartości deskryptora. Jeśli tak, to nie będzie to kontekst
this
instancji.
- Lepiej jest zmodyfikować oryginalny deskryptor niż zastąpić obecny, zwracając nowy deskryptor. Pozwala to na użycie wielu dekoratorów, które edytują deskryptor bez nadpisywania tego, co zrobił inny dekorator. Dzięki temu możesz użyć czegoś podobnego
@enumerable(false)
i @log
jednocześnie (przykład: Zły kontra Dobry )
- Przydatne : Argument typu
TypedPropertyDescriptor
może służyć do ograniczenia podpisów metod ( Przykład metody ) lub podpisów modułu dostępu ( Przykład modułu dostępu), w których można umieścić dekorator.
Przykład - z argumentami (fabryka dekoratorów)
Używając argumentów, musisz zadeklarować funkcję z parametrami dekoratora, a następnie zwrócić funkcję z podpisem przykładu bez argumentów.
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;
};
}
Dekorator metody statycznej
Podobne do dekoratora metod z pewnymi różnicami:
- Jego
target
parametrem jest sama funkcja konstruktora, a nie prototyp.
- Deskryptor jest zdefiniowany w funkcji konstruktora, a nie w prototypie.
Dekorator klasy
@isTestable
class MyClass {}
Parametr wykonania:
target
: Klasa, w której dekorator jest zadeklarowany ( TFunction extends Function
).
Przykład użycia : użycie interfejsu API metadanych do przechowywania informacji o klasie.
Dekorator nieruchomości
class MyClass {
@serialize
name: string;
}
Parametry realizacji:
target
: Prototyp klasy ( Object
).
propertyKey
: Nazwa właściwości ( string
| symbol
).
Przykład zastosowania : tworzenie @serialize("serializedName")
dekoratora i dodawanie nazwy właściwości do listy właściwości do serializacji.
Dekorator parametrów
class MyClass {
myMethod(@myDecorator myParameter: string) {}
}
Parametry realizacji:
target
: Prototyp klasy ( Function
- wydaje się, Function
że już nie działa. Powinieneś użyć any
lub Object
tutaj teraz, aby użyć dekoratora w dowolnej klasie. Lub określ typy klas, do których chcesz je ograniczyć)
propertyKey
: Nazwa metody ( string
| symbol
).
parameterIndex
: Indeks parametru na liście parametrów funkcji ( number
).
Prosty przykład
Szczegółowy przykład
@Injectable
dekoratorowi, zapoznaj się z