Decorators
Functions attached with an @ sign to classes and their members, which extend or change their behavior.
- Returns
- For a class, method, and accessor: a member that replaces the original, or nothing (no change). A field decorator can return a function that transforms the initial value.
Example
#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
Definition and usage
#A decorator is an ordinary function that you attach with an @ sign to a class or one of its members, for example @logged above a method. It runs once, at the moment the class is defined, and receives the decorated member plus a context object describing it. If it returns a new function, that function replaces the original method. Logic you write once, for example logging, timing, or a permission check, can then be attached to any method with a single line.
Since version 5.0, TypeScript supports the standard decorators from the TC39 proposal, with no extra option needed. You can use them on classes, methods, getters and setters, fields, and fields with the accessor modifier. They donât work on plain functions or on parameters, where the compiler reports âDecorators are not valid here.â With a target lower than ESNext, the compiler turns decorators into plain JavaScript with helper functions.
Many popular libraries, for example NestJS and TypeORM, use an older, experimental version of decorators, turned on with the experimentalDecorators option. Decorators like that receive different arguments (the target object, the property name, and a descriptor), can mark parameters, and work together with the emitDecoratorMetadata option. The two versions are incompatible: a decorator written for one wonât work in the other.
Syntax
#function decorator(value, context) {
return replacement // optional
}
@decorator
class SomeClass {
@decorator method() { ⊠}
@decorator field = 1
}Decorator arguments
#value
depends on the member
The decorated member: a class, method, getter, or setter, and for anaccessorfield, an object withgetandset. For plain fields, itâsundefined, because at the moment the class is defined, the field doesnât have a value yet.context
ClassMethodDecoratorContext and related types
A description of the member:kind(the type, for example"method"or"field"),name,static,private, and theaddInitializer()method, which registers code to run during initialization.
More examples
#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']
Good practices
#- A decorator with arguments, for example
@clamp(12, 24), is a function that returns the actual decorator. Most decorators from libraries are built that way. - A field decorator only changes the initial value. To control every later write, mark the field with the
accessorkeyword and use a decorator that replaces itsgetandset. - Check that
tsconfig.jsondoesnât haveexperimentalDecorators: true. If it does, the old signatures apply, and the examples on this page wonât compile.
Related entries
#- public, private, protectedAccess modifiers that control where a classâs fields and methods can be used from.
- abstract classA base class you canât create directly, with methods for its descendants to fill in.
- implementsA declaration that a class fulfills the contract described by an interface.
- Function typesTyping parameters, the return value, and functions themselves as values.
- Generics <T>Types and functions with a type parameter that work for many types without losing precision.
Spotted a mistake or missing an example? Write to us.