Back to TypeScript tutorials
Advanced13 min read

Decorators

Metaprogramming with decorators for cross-cutting concerns in classes, methods, and properties.

Decorator Stages and Standards

TC39 stage 3 decorators (TypeScript 5.0+ with `experimentalDecorators` disabled) follow a new standard distinct from legacy experimental decorators used by Angular and older NestJS versions. Verify which decorator model your framework targets before adopting patterns.

Decorators are functions applied to class declarations, methods, accessors, fields, or parameters, transforming or wrapping the decorated target at definition time.

  • Stage 3 vs legacy experimental decorators
  • Check framework compatibility first
  • Applied at class definition time

Class and Method Decorators

Class decorators receive the constructor and can replace or extend it — used for registration, dependency injection metadata, and serialization setup. Method decorators wrap the original method, enabling logging, timing, authorization checks, and memoization.

Keep decorator logic thin — heavy work in decorators obscures behavior. Compose small decorators rather than one decorator that does everything.

  • Class decorators for registration/DI
  • Method decorators wrap behavior
  • Compose small focused decorators
function logged(_target: unknown, ctx: ClassMethodDecoratorContext) {
  return function (this: unknown, ...args: unknown[]) {
    console.log('calling', ctx.name);
  };
}

Property and Parameter Decorators

Field decorators can customize access or initialization — common in validation frameworks attaching metadata. Parameter decorators mark injection points in DI containers (NestJS `@Inject()` pattern).

Legacy parameter decorators only receive metadata — they cannot replace parameters. Modern frameworks store reflection metadata via `reflect-metadata` for runtime injection resolution.

  • Field decorators for metadata/validation
  • Parameter decorators mark DI injection
  • Often paired with reflect-metadata

Framework Usage Patterns

Angular uses decorators extensively (`@Component`, `@Injectable`). NestJS uses them for controllers, guards, and pipes. Understanding decorator execution order matters when multiple decorators stack on the same target.

Outside these ecosystems, decorators are less common in application code. Prefer explicit middleware, higher-order functions, or composition when not using a decorator-native framework.

  • Angular and NestJS are decorator-centric
  • Decorator order affects composition
  • Prefer functions outside decorator frameworks

Testing and Debugging

Decorators modify classes at load time — bugs may appear before any test runs. Unit test decorated classes in isolation and verify metadata side effects separately from business logic.

Source maps and decorator transpilation can complicate stack traces. Document custom decorators on team wikis so reviewers understand implicit behavior applied at import time.

  • Test decorated classes in isolation
  • Document custom decorator behavior
  • Watch stack trace complexity

Get In Touch


Ready to discuss your next project? Drop me a message.