← Back to TypeScript Course | Chapter 10: Decorators | Lesson 1 of 7

Introduction to Decorators

Decorators are functions that can observe or modify classes and class members in TypeScript. Modern TypeScript supports standard decorators for classes, methods, getters, setters, fields, and auto-accessors.
Syntax
typescript
function decoratorName(target: any, context: ClassMethodDecoratorContext) {
  // wrap or inspect the decorated member
}

class ClassName {
  @decoratorName
  methodName() { }
}

What Is a Decorator?

A decorator is a function applied with the @ syntax directly above a class, method, property, or parameter; it receives information about the declaration it's attached to and can observe or modify it.

Example: What Is a Decorator?

typescript
function logged(target: any, context: ClassMethodDecoratorContext) {
  console.log(`Decorator applied to ${String(context.name)}`);
}
class Greeter {
  @logged
  greet() {
    return "hi";
  }
}
new Greeter().greet();

Decorator Syntax

Decorators are written immediately before the declaration they decorate, and multiple decorators can be stacked on the same declaration, applying in a specific, well-defined order.

Example: Decorator Syntax

typescript
function first(target: any, ctx: ClassMethodDecoratorContext) {
  console.log("first decorator on", String(ctx.name));
}
function second(target: any, ctx: ClassMethodDecoratorContext) {
  console.log("second decorator on", String(ctx.name));
}
class Example {
  @first
  @second
  run() {}
}
new Example().run();

Decorator Context

Standard decorators receive a context object describing what is being decorated — its kind, name, and other metadata — which the decorator can use to decide how to behave.

Example: Decorator Context

typescript
function describe(target: any, context: ClassMethodDecoratorContext) {
  console.log("Decorating", context.kind, String(context.name));
}
class Service {
  @describe
  start() {}
}
new Service();

Replacing Decorated Values

Some decorators can return a compatible replacement value; method decorators, for example, commonly return a wrapped version of the original method that adds behavior like logging around the call.

Example: Replacing Decorated Values

typescript
function logCall(target: any, context: ClassMethodDecoratorContext) {
  return function (this: any, ...args: any[]) {
    console.log("Calling", String(context.name));
    return target.call(this, ...args);
  };
}
class Calculator {
  @logCall
  add(a: number, b: number) {
    return a + b;
  }
}
console.log(new Calculator().add(2, 3));

Enabling Modern Decorators

In current TypeScript, standard decorators work without needing the legacy experimentalDecorators compiler flag, following the newer, TC39-aligned decorators proposal instead of the older, non-standard implementation.

Example: Enabling Modern Decorators

typescript
// Modern (TC39) decorators work without experimentalDecorators:
function marker(target: any, context: ClassMethodDecoratorContext) {}
class Widget {
  @marker
  render() {
    return "rendered";
  }
}
console.log(new Widget().render());
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Using decorators without the right compiler setup, since legacy decorators need experimentalDecorators while standard ones expect the newer signature.
  2. Writing a decorator with the old (target, key, descriptor) signature under standard decorators, where it receives (value, context).
  3. Assuming @logged runs each time the method is called, when the decorator function runs once when the class is defined.
🔒

Chapter Quiz — Complete all 7 topics to unlock

0/7 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.