Décorateurs
Des fonctions attachées avec un signe @ à des classes et à leurs membres, qui étendent ou modifient leur comportement.
- Renvoie
- Pour une classe, une méthode et un accesseur : un membre qui remplace l’original, ou rien (pas de changement). Un décorateur de champ peut renvoyer une fonction qui transforme la valeur initiale.
Exemple
#function logged<This, Args extends unknown[], Result>(
method: (this: This, ...args: Args) => Result,
context: ClassMethodDecoratorContext<This>
) {
const name = String(context.name)
return function (this: This, ...args: Args): Result {
console.log(`LOG: ${name}(${args.join(', ')})`)
return method.apply(this, args)
}
}
class ScoreBoard {
private total = 0
@logged
add(points: number) {
this.total += points
return this.total
}
}
const board = new ScoreBoard()
board.add(20)
console.log(board.add(15))LOG: add(20) LOG: add(15) 35
Définition et utilisation
#Un décorateur est une fonction ordinaire que vous attachez avec un signe @ à une classe ou à l’un de ses membres, par exemple @logged au-dessus d’une méthode. Il s’exécute une fois, au moment où la classe est définie, et reçoit le membre décoré ainsi qu’un objet context qui le décrit. S’il renvoie une nouvelle fonction, celle-ci remplace la méthode d’origine. Une logique écrite une seule fois, par exemple la journalisation, la mesure du temps ou la vérification des droits, peut alors être attachée à n’importe quelle méthode en une seule ligne.
Depuis la version 5.0, TypeScript prend en charge les décorateurs standards de la proposition TC39, sans aucune option supplémentaire. Vous pouvez les utiliser sur les classes, les méthodes, les getters et setters, les champs, ainsi que les champs avec le modificateur accessor. Ils ne fonctionnent pas sur les fonctions ordinaires ni sur les paramètres, où le compilateur signale « Decorators are not valid here ». Avec une target inférieure à ESNext, le compilateur transforme les décorateurs en JavaScript ordinaire à l’aide de fonctions utilitaires.
De nombreuses bibliothèques populaires, par exemple NestJS et TypeORM, utilisent une version plus ancienne et expérimentale des décorateurs, activée par l’option experimentalDecorators. Ces décorateurs reçoivent des arguments différents (l’objet cible, le nom et un descripteur de propriété), peuvent marquer des paramètres, et fonctionnent avec l’option emitDecoratorMetadata. Les deux versions sont incompatibles : un décorateur écrit pour l’une ne fonctionnera pas dans l’autre.
Syntaxe
#function decorator(value, context) {
return replacement // optionnel
}
@decorator
class SomeClass {
@decorator method() { … }
@decorator field = 1
}Arguments du décorateur
#value
dépend du membre
Le membre décoré : une classe, une méthode, un getter ou un setter, et pour un champaccessor, un objet avecgetetset. Pour un champ ordinaire, c’estundefined, car au moment où la classe est définie, le champ n’a pas encore de valeur.context
ClassMethodDecoratorContext et types apparentés
Une description du membre :kind(le type, par exemple"method"ou"field"),name(le nom),static,private, ainsi que la méthodeaddInitializer(), qui enregistre du code à exécuter lors de l’initialisation.
Plus d’exemples
#function clamp(min: number, max: number) {
return function (_value: undefined, _context: ClassFieldDecoratorContext<unknown, number>) {
return (initial: number) => Math.min(max, Math.max(min, initial))
}
}
class ReaderSettings {
@clamp(12, 24) fontSize = 40
@clamp(1, 3) columns = 0
}
console.log(new ReaderSettings())ReaderSettings { fontSize: 24, columns: 1 }const registry: string[] = []
function register(_value: new (...args: any[]) => object, context: ClassDecoratorContext) {
registry.push(String(context.name))
}
@register
class QuizTask {}
@register
class CodeTask {}
console.log(registry)['QuizTask', 'CodeTask']
Bonnes pratiques
#- Un décorateur avec des arguments, par exemple
@clamp(12, 24), est une fonction qui renvoie le véritable décorateur. C’est ainsi que sont construits la plupart des décorateurs des bibliothèques. - Un décorateur de champ ne change que la valeur initiale. Pour contrôler chaque écriture ultérieure, marquez le champ avec le mot-clé
accessoret utilisez un décorateur qui remplace songetet sonset. - Vérifiez que
tsconfig.jsonne contient pasexperimentalDecorators: true. Dans ce cas, ce sont les anciennes signatures qui s’appliquent, et les exemples de cette page ne compileront pas.
Entrées associées
#- public, private, protectedDes modificateurs d’accès qui déterminent d’où les champs et méthodes d’une classe peuvent être utilisés.
- abstract classUne classe de base que vous ne pouvez pas créer directement, avec des méthodes à compléter par ses descendants.
- implementsUne déclaration indiquant qu’une classe respecte le contrat décrit par une interface.
- Types de fonctionsTyper les paramètres, la valeur de retour et les fonctions elles-mêmes en tant que valeurs.
- Génériques <T>Types et fonctions avec un paramètre de type, qui fonctionnent pour plusieurs types sans perdre en précision.
Vous voyez une erreur ou il manque un exemple ? Écrivez-nous.