How to Use Decorators in TypeScript

Use decorators in TypeScript when classes, methods, properties, or parameters need metadata, automatic behavior, or reusable cross-cutting logic. They are common in frameworks like :contentReference[oaicite:0]{index=0}, :contentReference[oaicite:1]{index=1}, and :contentReference[oaicite:2]{index=2}.

What you’ll build or solve

You’ll learn how to use decorators in TypeScript with class and method decorators. You’ll also know when decorators are better than manual repetitive logic.

When this approach works best

This approach is the right choice when behavior should be attached declaratively to existing classes or methods.

Common real-world scenarios include:

  • Route handlers
  • Validation metadata
  • ORM entities
  • Logging wrappers
  • Dependency injection

This is a bad idea when the same result is clearer with a plain function wrapper.

Prerequisites

You only need:

  • Advanced TypeScript basics
  • Classes and methods
  • experimentalDecorators enabled in tsconfig.json

Step-by-step instructions

Step 1: Enable decorators in TypeScript config

Decorators require compiler support.

{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

Without this, decorator syntax will fail.

Step 2: Create a class decorator

A decorator is a function that receives the class.

function Logger(target: Function): void {
  console.log(`Registered: ${target.name}`);
}

@Logger
class UserService {}

This runs when the class is defined.

It is useful for metadata registration.

Step 3: Create a method decorator

Method decorators can wrap behavior.

function LogCall(
  target: object,
  key: string,
  descriptor: PropertyDescriptor
): void {
  const original = descriptor.value;

  descriptor.value = function (...args: unknown[]) {
    console.log(`Calling ${key}`);
    return original.apply(this, args);
  };
}

Apply it to a method.

class PaymentService {
  @LogCall
  charge(): void {
    console.log("Charged");
  }
}

This keeps reusable wrappers clean.

What to look for:

  • Decorators add metadata or behavior
  • Enable experimentalDecorators
  • Great for frameworks and DI
  • Method decorators can wrap logic
  • Use sparingly for clarity

Examples you can copy

Logging decorator

@Logger
class ApiService {}

Method wrapper

@LogCall
save()

Framework route

@Get("/users")

Common mistakes and how to fix them

Mistake 1: Forgetting compiler support

What the reader might do:

Use @Logger without config.

Why it breaks: TypeScript rejects decorator syntax.

Corrected approach:

Enable experimentalDecorators.

Mistake 2: Overusing decorators for simple helpers

What the reader might do:

Decorate tiny utility methods.

Why it breaks: indirection hurts readability.

Corrected approach:

Use plain wrappers when simpler.

Mistake 3: Mutating descriptors incorrectly

What the reader might do:

Replace the method without preserving this.

Why it breaks: instance methods lose context.

Corrected approach:

Use original.apply(this, args).

Troubleshooting

If syntax errors appear, enable decorators in tsconfig.json.

If methods lose context, preserve this.

If logic feels hidden, prefer plain functions.

If using frameworks, follow their decorator conventions.

Quick recap

  • Decorators attach reusable behavior declaratively
  • Enable experimentalDecorators
  • Great for frameworks and metadata
  • Preserve this in method wrappers
  • Prefer simpler patterns when possible