Ho finito per giocare con i decoratori e ho deciso di documentare ciò che ho capito per chiunque voglia approfittare di questo prima che venga pubblicata qualsiasi documentazione. Non esitare a modificarlo in caso di errori.
Punti generali
- I decoratori vengono chiamati quando viene dichiarata la classe, non quando un oggetto viene istanziato.
- Più decoratori possono essere definiti sulla stessa Classe / Proprietà / Metodo / Parametro.
- I decoratori non sono ammessi ai costruttori.
Un decoratore valido dovrebbe essere:
- Assegnabile a uno dei tipi di Decoratore (
ClassDecorator | PropertyDecorator | MethodDecorator | ParameterDecorator
).
- Restituisce un valore (nel caso di decoratori di classe e decoratore di metodi) che è assegnabile al valore decorato.
Riferimento
Metodo / Decoratore di accessori formale
Parametri di attuazione:
target
: Il prototipo della classe ( Object
).
propertyKey
: Il nome del metodo ( string
| symbol
).
descriptor
: A TypedPropertyDescriptor
- Se non hai familiarità con le chiavi di un descrittore, consiglierei di leggerlo in questa documentazione su Object.defineProperty
(è il terzo parametro).
Esempio: senza argomenti
Uso:
class MyClass {
@log
myMethod(arg: string) {
return "Message -- " + arg;
}
}
Implementazione:
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;
}
Ingresso:
new MyClass().myMethod("testing");
Produzione:
I metodi args sono: ["testing"]
Il valore restituito è: Messaggio - test
Appunti:
- Non utilizzare la sintassi della freccia durante l'impostazione del valore del descrittore. Se lo fai, il contesto di
this
non sarà l'istanza.
- È meglio modificare il descrittore originale piuttosto che sovrascrivere quello corrente restituendo un nuovo descrittore. Ciò consente di utilizzare più decoratori che modificano il descrittore senza sovrascrivere ciò che ha fatto un altro decoratore. In questo modo puoi utilizzare qualcosa di simile
@enumerable(false)
e @log
allo stesso tempo (Esempio: Bad vs Good )
- Utile : l'argomento tipo di
TypedPropertyDescriptor
può essere utilizzato per limitare le firme dei metodi ( Esempio di metodo ) o le firme degli accessori ( Esempio di accessori ) su cui è possibile applicare il decoratore.
Esempio: con argomenti (fabbrica di decorazioni)
Quando si utilizzano gli argomenti, è necessario dichiarare una funzione con i parametri del decoratore, quindi restituire una funzione con la firma dell'esempio senza argomenti.
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;
};
}
Decoratore con metodo statico
Simile a un decoratore di metodi con alcune differenze:
- Suo
target
parametro è la funzione di costruzione stessa e non il prototipo.
- Il descrittore è definito sulla funzione di costruzione e non sul prototipo.
Decoratore di classe
@isTestable
class MyClass {}
Parametro di attuazione:
target
: La classe in cui viene dichiarato il decoratore ( TFunction extends Function
).
Esempio di utilizzo : utilizzo dell'API dei metadati per memorizzare informazioni su una classe.
Decoratore di proprietà
class MyClass {
@serialize
name: string;
}
Parametri di attuazione:
target
: Il prototipo della classe (Object
).
propertyKey
: Il nome della proprietà ( string
| symbol
).
Esempio di utilizzo : creazione di un @serialize("serializedName")
decoratore e aggiunta del nome della proprietà a un elenco di proprietà da serializzare.
Decoratore di parametri
class MyClass {
myMethod(@myDecorator myParameter: string) {}
}
Parametri di attuazione:
target
: Il prototipo della classe ( Function
—sembra Function
che non funzioni più. Dovresti usare any
o Object
qui ora per usare il decoratore all'interno di qualsiasi classe. O specificare i tipi di classe a cui vuoi limitarlo)
propertyKey
: Il nome del metodo ( string
| symbol
).
parameterIndex
: L'indice del parametro nell'elenco dei parametri della funzione ( number
).
Semplice esempio
Esempi dettagliati
@Injectable
in un decoratore,