Am Ende habe ich mit Dekorateuren herumgespielt und beschlossen, zu dokumentieren, was ich für jeden herausgefunden habe, der dies nutzen möchte, bevor eine Dokumentation herauskommt. Bitte zögern Sie nicht, dies zu bearbeiten, wenn Sie Fehler sehen.
Allgemeine Punkte
- Dekoratoren werden aufgerufen, wenn die Klasse deklariert wird - nicht, wenn ein Objekt instanziiert wird.
- Mehrere Dekorateure können für dieselbe Klasse / Eigenschaft / Methode / Parameter definiert werden.
- Dekorateure sind auf Konstruktoren nicht erlaubt.
Ein gültiger Dekorateur sollte sein:
- Zuweisbar auf einen der Decorator-Typen (
ClassDecorator | PropertyDecorator | MethodDecorator | ParameterDecorator
).
- Gibt einen Wert zurück (im Fall von Klassendekoratoren und Methodendekoratoren), der dem dekorierten Wert zugewiesen werden kann.
Referenz
Method / Formal Accessor Decorator
Implementierungsparameter:
target
: Der Prototyp der Klasse ( Object
).
propertyKey
: Der Name der Methode ( string
| symbol
).
descriptor
: A TypedPropertyDescriptor
- Wenn Sie mit den Schlüsseln eines Deskriptors nicht vertraut sind, würde ich empfehlen, darüber in dieser Dokumentation zu lesen Object.defineProperty
(dies ist der dritte Parameter).
Beispiel - Ohne Argumente
Verwenden:
class MyClass {
@log
myMethod(arg: string) {
return "Message -- " + arg;
}
}
Implementierung:
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;
}
Eingang:
new MyClass().myMethod("testing");
Ausgabe:
Die Methodenargumente sind: ["Testen"]
Der Rückgabewert lautet: Nachrichtentest
Anmerkungen:
- Verwenden Sie keine Pfeilsyntax, wenn Sie den Wert des Deskriptors festlegen. Der Kontext von
this
wird nicht der der Instanz sein, wenn Sie dies tun.
- Es ist besser, den ursprünglichen Deskriptor zu ändern, als den aktuellen zu überschreiben, indem Sie einen neuen Deskriptor zurückgeben. Auf diese Weise können Sie mehrere Dekorateure verwenden, die den Deskriptor bearbeiten, ohne zu überschreiben, was ein anderer Dekorateur getan hat. Auf diese Weise können Sie so etwas wie
@enumerable(false)
und @log
gleichzeitig verwenden (Beispiel: Schlecht gegen Gut )
- Nützlich : Mit dem Argument type von
TypedPropertyDescriptor
können Sie einschränken, auf welche Methodensignaturen ( Methodenbeispiel ) oder Accessorsignaturen ( Accessor-Beispiel ) der Dekorator angewendet werden kann.
Beispiel - Mit Argumenten (Decorator Factory)
Wenn Sie Argumente verwenden, müssen Sie eine Funktion mit den Parametern des Dekorateurs deklarieren und dann eine Funktion mit der Signatur des Beispiels ohne Argumente zurückgeben.
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;
};
}
Static Method Decorator
Ähnlich einem Methodendekorateur mit einigen Unterschieden:
- Sein
target
Parameter ist die Konstruktorfunktion selbst und nicht der Prototyp.
- Der Deskriptor wird in der Konstruktorfunktion und nicht im Prototyp definiert.
Klassendekorateur
@isTestable
class MyClass {}
Implementierungsparameter:
target
: Die Klasse, für die der Dekorateur deklariert ist ( TFunction extends Function
).
Anwendungsbeispiel : Verwenden der Metadaten-API zum Speichern von Informationen zu einer Klasse.
Property Decorator
class MyClass {
@serialize
name: string;
}
Implementierungsparameter:
target
: Der Prototyp der Klasse ( Object
).
propertyKey
: Der Name der Eigenschaft ( string
| symbol
).
Anwendungsbeispiel : Erstellen eines @serialize("serializedName")
Dekorators und Hinzufügen des Eigenschaftsnamens zu einer Liste der zu serialisierenden Eigenschaften.
Parameter Decorator
class MyClass {
myMethod(@myDecorator myParameter: string) {}
}
Implementierungsparameter:
target
: Der Prototyp der Klasse ( Function
- es scheint Function
nicht mehr zu funktionieren. Sie sollten any
oder Object
hier jetzt verwenden, um den Dekorator in einer Klasse zu verwenden. Oder geben Sie die Klassentypen an, auf die Sie ihn einschränken möchten.)
propertyKey
: Der Name der Methode ( string
| symbol
).
parameterIndex
: Der Parameterindex in der Liste der Funktionsparameter ( number
).
Einfaches Beispiel
Detaillierte Beispiele
@Injectable
in einen Dekorateur injizieren möchten , beziehen Sie sich auf