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 Case | Decorator Type | Example |
|---|---|---|
| Logging | Method/Class | @Log |
| Authorization | Method | @Authorized |
| Input Validation | Property | @IsEmail, @IsString |
| Dependency Injection | Class/Property | @Inject, @Service |
| ORM Field Mapping | Property | @Column, @PrimaryKey |
| Metadata (Reflect) | All | Used 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": trueintsconfig.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
getorsetfunctions 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 :
