2 min read

TypeScript Decorators

Decorators provide a way to add both annotations and a meta-programming syntax for class declarations and members. They are a stage 3 proposal for JavaScript and are available as an experimental feature in TypeScript.

1. Configuration

To use decorators, you must enable the experimentalDecorators compiler option in your tsconfig.json:

{
  "compilerOptions": {
    "target": "ES5",
    "experimentalDecorators": true
  }
}

2. What is a Decorator?

A Decorator is a special kind of declaration that can be attached to a class declaration, method, accessor, property, or parameter. Decorators use the form @expression, where expression must evaluate to a function that will be called at runtime with information about the decorated declaration.

3. Class Decorators

A Class Decorator is declared just before a class declaration. It is applied to the constructor of the class and can be used to observe, modify, or replace a class definition.

function Sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

@Sealed
class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
  greet() {
    return "Hello, " + this.greeting;
  }
}

4. Method Decorators

A Method Decorator is declared just before a method declaration. It can be used to observe, modify, or replace a method definition.

The decorator function receives three arguments:

  1. The constructor function (for static members) or the prototype (for instance members).
  2. The name of the member.
  3. The Property Descriptor for the member.
function Enumerable(value: boolean) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    descriptor.enumerable = value;
  };
}

class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }

  @Enumerable(false)
  greet() {
    return "Hello, " + this.greeting;
  }
}

5. Decorator Factories

If you want to customize how a decorator is applied to a declaration, you can write a decorator factory. A decorator factory is simply a function that returns the expression that will be called by the decorator at runtime.

function Log(prefix: string) {
    return function(target: any) {
        console.log(`${prefix}: Class initialized`);
    }
}

@Log("INFO")
class Person {
    constructor(public name: string) {}
}
// Output: INFO: Class initialized

programming/javascript/typescript/typescript