Advanced Lesson · 13

Decorators

Special annotations that attach metadata or behaviour to classes, methods, and properties — the foundation of Angular and NestJS.

01 What Are Decorators?

Decorators are functions that wrap other code. They start with @ and are placed directly above a class, method, property, or parameter. When TypeScript sees a decorator, it calls that function and passes the decorated target to it.

⚠️ Enable decorators in tsconfig.json: set "experimentalDecorators": true and "emitDecoratorMetadata": true.

tsconfig.json (required)
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "target": "ES2021"
  }
}

02 Class Decorators

A class decorator is applied to the constructor of a class. It can add properties, replace the constructor, or just log information.

class-decorator.ts
// A simple class decorator
function Sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

@Sealed
class BankAccount {
  owner: string;
  constructor(owner: string) {
    this.owner = owner;
  }
}

// Decorator with arguments (decorator factory)
function Controller(path: string) {
  return function(constructor: Function) {
    Reflect.defineMetadata('path', path, constructor);
  };
}

@Controller('/users')
class UserController {
  // handles routes starting with /users
}

03 Method Decorators

Method decorators can intercept, wrap, or modify a method's behavior — perfect for logging, authorization checks, and caching.

method-decorator.ts
// Log every method call automatically
function Log(
  target: any,
  key: string,
  descriptor: PropertyDescriptor
) {
  const original = descriptor.value;

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

class Calculator {
  @Log
  add(a: number, b: number): number {
    return a + b;
  }
}

const calc = new Calculator();
calc.add(3, 4);
// → Calling add with: [3, 4]
// → add returned: 7

04 Property Decorators

Property decorators are placed above class fields to add metadata or validation.

property-decorator.ts
function MinLength(min: number) {
  return function(target: any, propertyKey: string) {
    let value: string;

    Object.defineProperty(target, propertyKey, {
      get() { return value; },
      set(newVal: string) {
        if (newVal.length < min) {
          throw new Error(`${propertyKey} must be at least ${min} chars`);
        }
        value = newVal;
      }
    });
  };
}

class User {
  @MinLength(3)
  name: string = "";
}

const user = new User();
user.name = "Alice"; // ✅
// user.name = "Al"; ❌ Error: name must be at least 3 chars

05 Real-World: NestJS

NestJS uses decorators as its entire API. Here's how a real NestJS controller looks:

users.controller.ts (NestJS)
import { Controller, Get, Post, Body, Param } from '@nestjs/common';

@Controller('users')        // base route: /users
export class UsersController {

  @Get()                    // GET /users
  findAll() {
    return ['alice', 'bob'];
  }

  @Get(':id')               // GET /users/:id
  findOne(@Param('id') id: string) {
    return `User #${id}`;
  }

  @Post()                   // POST /users
  create(@Body() body: CreateUserDto) {
    return body;
  }
}

🏛️ Every @Get(), @Post(), @Body() you see in NestJS is a decorator. That's the power of this feature.

06 Types at a Glance

@ClassDecorator
Applied to the class constructor. Can seal, freeze, or augment the class.
@MethodDecorator
Wraps a method. Receives target, key, and property descriptor.
@PropertyDecorator
Applied to class fields. Receives target and property key.
@ParameterDecorator
Applied to constructor/method parameters. Receives target, key, and index.
@AccessorDecorator
Applied to getters/setters. Works like method decorators.
Previous
Lesson 12 — Utility Types
You are here
13 / 17
Next Lesson
Lesson 14 — tsconfig.json