TypeScript – Decorators: Powerful Meta-Programming for Classes

Introduction – What Are Decorators in TypeScript?

Decorators in TypeScript are special functions that can annotate and modify classes, methods, properties, or parameters. Inspired by languages like Python and Java, decorators provide a way to add metadata, logging, validation, or transformation to existing definitions without changing their core logic.

Decorators are part of the experimental features in TypeScript, introduced to support meta-programming in a clean, declarative way. They are particularly useful in frameworks like Angular, NestJS, and TypeORM.

In this guide, you’ll learn:

  • What decorators are and how they work
  • Syntax and use cases for each decorator type
  • How to enable decorators in your project
  • Practical examples and best practices

Enabling Decorators in TypeScript

Since decorators are an experimental feature, you must enable them in tsconfig.json:

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

You must also use a compatible build tool like ts-node, Webpack, or Babel.


What Is a Decorator?

A decorator is a function applied to a class or class member (property, method, accessor, parameter). It can modify the behavior, add metadata, or wrap logic.

Decorator Signature:

function MyDecorator(target: any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor) {
  // logic here
}

Types of Decorators in TypeScript

1️⃣ Class Decorators

Applied to the class constructor and can be used to replace or modify the class definition.

function Logger(constructor: Function) {
  console.log(`Class ${constructor.name} loaded`);
}

@Logger
class Person {
  constructor(public name: string) {}
}

This logs a message whenever the class is declared.


2️⃣ Property Decorators

Applied to class properties. Useful for validation or metadata tagging.

function ReadOnly(target: any, key: string) {
  Object.defineProperty(target, key, {
    writable: false
  });
}

class Book {
  @ReadOnly
  title = "TypeScript Guide";
}

The @ReadOnly decorator makes title non-writable.


3️⃣ Method Decorators

Applied to class methods. Useful for logging, authentication, caching, etc.

function Log(target: any, key: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`Called ${key} with`, args);
    return originalMethod.apply(this, args);
  };
}

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

This logs every call to the add() method.


4️⃣ Accessor Decorators

Used on get or set methods. Works similarly to method decorators.

function Capitalize(target: any, key: string, descriptor: PropertyDescriptor) {
  const original = descriptor.get!;
  descriptor.get = function () {
    const result = original.call(this);
    return typeof result === "string" ? result.toUpperCase() : result;
  };
}

class Product {
  constructor(private _name: string) {}

  @Capitalize
  get name() {
    return this._name;
  }
}

This decorator capitalizes the output of get name().


5️⃣ Parameter Decorators

Used to annotate method parameters.

function LogParameter(target: Object, methodName: string | symbol, parameterIndex: number) {
  console.log(`Parameter at position ${parameterIndex} in ${String(methodName)} has been decorated.`);
}

class Greeter {
  greet(@LogParameter name: string) {
    return `Hello, ${name}`;
  }
}

Mostly used for metadata generation in frameworks like Angular and NestJS.


Real-World Use Cases of Decorators

Use CaseDecorator TypeExample
LoggingMethod/Class@Log
AuthorizationMethod@Authorized
Input ValidationProperty@IsEmail, @IsString
Dependency InjectionClass/Property@Inject, @Service
ORM Field MappingProperty@Column, @PrimaryKey
Metadata (Reflect)AllUsed with reflect-metadata

Composing Multiple Decorators

Decorators are composable and applied from bottom to top (right to left).

function A() {
  return function (target: any) {
    console.log("Decorator A");
  };
}

function B() {
  return function (target: any) {
    console.log("Decorator B");
  };
}

@A()
@B()
class Demo {}

Output:

Decorator B
Decorator A

Reflect Metadata Support

You can use the reflect-metadata library to enable runtime metadata reflection.

Install:

npm install reflect-metadata

Then import it once in your project:

import "reflect-metadata";

Example:

function Type(type: string) {
  return Reflect.metadata("design:type", type);
}

class Car {
  @Type("string")
  model!: string;
}

Summary – TypeScript Decorators

Decorators offer a declarative, reusable way to enhance class functionality without altering core logic. They are widely adopted in frameworks and libraries that require meta-programming or dependency injection.

Key Takeaways:

  • Decorators are special functions used to annotate classes and members.
  • They can be used for logging, validation, metadata, and more.
  • Enable via "experimentalDecorators": true in tsconfig.json.
  • Work well with class-based design patterns.
  • Common in Angular, NestJS, TypeORM, and other modern TS frameworks.

Real-world relevance:

Decorators are essential for building scalable, enterprise-grade TypeScript applications using modern design patterns.


FAQs – TypeScript Decorators

Are decorators available by default in TypeScript?

No. You must enable them manually using "experimentalDecorators": true in tsconfig.json.


What is the order of decorator execution?

Decorators execute from bottom to top β€” meaning the last declared decorator runs first.


Do decorators work with plain JavaScript?

Not natively. Decorators are a TypeScript feature and need transpilation. However, future versions of JavaScript may include official support.


What is the difference between method and accessor decorators?

  • Method decorators modify or wrap class methods.
  • Accessor decorators apply specifically to get or set functions and modify how values are accessed.

Which libraries use decorators?

Popular libraries that rely on decorators include:

  • Angular (@Component, @Injectable)
  • NestJS (@Controller, @Get)
  • TypeORM (@Entity, @Column)
  • class-validator (@IsEmail, @Length)

Can I use decorators with interfaces?

No. Decorators only work on classes and their members β€” not on interfaces or type aliases.


Share Now :
Share

TypeScript β€” Decorators

Or Copy Link

CONTENTS
Scroll to Top