Decorators are a powerful way to enhance classes and their members (methods or properties) without touching their original code directly. 🎯
They let you decorate behaviour in a clean and reusable way. Like adding toppings to a pizza 🍕
⚠️ Decorators are a Stage-3 proposal in JavaScript. You can use them with TypeScript or Babel.
🔍 What is a Decorator?
A decorator is a special function you can attach to:
- A class
- A class method
- A class property
It looks like this:
@myDecorator
class MyClass {}Or for methods:
class MyClass {
  @log
  doSomething() {}
}⚙️ How Do Decorators Work Behind the Scenes?
Think of a decorator as a function that wraps the original function, property, or class to change its behavior.
Here's what happens behind the scenes for method decorators:
- When the class is defined, decorators are executed.
- The decorator function receives three arguments:
- 
target: The class prototype (for instance methods) or constructor (for static methods)
- 
propertyKey: The name of the method/property being decorated
- 
descriptor: The property descriptor that describes the method- The decorator can change the method (e.g., add logging) by modifying the descriptor.
 
Behind-the-scenes sketch:
function log(target, propertyKey, descriptor) {
  // Modify the original function
  const originalMethod = descriptor.value;
  descriptor.value = function (...args) {
    console.log(`Calling ${propertyKey} with`, args);
    return originalMethod.apply(this, args);
  };
  return descriptor;
}Decorators don’t execute at runtime like normal code — they execute when the class is first defined.
🧪 Basic Example – Logging Function Calls
Let’s see a working example:
function log(target, propertyName, descriptor) {
  const original = descriptor.value;
  descriptor.value = function (...args) {
    console.log(`📞 ${propertyName} called with`, args);
    const result = original.apply(this, args);
    console.log(`✅ ${propertyName} returned`, result);
    return result;
  };
  return descriptor;
}
class Calculator {
  @log
  add(a, b) {
    return a + b;
  }
}
const calc = new Calculator();
calc.add(5, 3);🧰 Real-World Use Cases
1. ✅ Logging and Debugging
Great for tracing code behavior during development.
2. 🔐 Authorization Guards
function requireAdmin(target, key, descriptor) {
  const original = descriptor.value;
  descriptor.value = function (...args) {
    if (!this.isAdmin) {
      throw new Error("⛔️ Access denied");
    }
    return original.apply(this, args);
  };
  return descriptor;
}
class Dashboard {
  constructor(isAdmin) {
    this.isAdmin = isAdmin;
  }
  @requireAdmin
  deleteUser() {
    console.log("🗑️ User deleted");
  }
}
const admin = new Dashboard(true);
admin.deleteUser(); // 🗑️ User deleted
const guest = new Dashboard(false);
guest.deleteUser(); // ⛔️ Error: Access denied3. 🧹 Auto-Binding Methods
function autobind(target, key, descriptor) {
  const original = descriptor.value;
  return {
    configurable: true,
    enumerable: false,
    get() {
      return original.bind(this);
    },
  };
}
class Printer {
  message = "💨 Hello from Printer!";
  @autobind
  print() {
    console.log(this.message);
  }
}
const p = new Printer();
const printFn = p.print;
printFn(); // 💨 Hello from Printer!🔬 Types of Decorators
JavaScript (and especially TypeScript) supports different types of decorators:
| Type | Target | Purpose | 
|---|---|---|
| Class decorator | Whole class | Modify or enhance a class | 
| Method decorator | Class method | Wrap or replace a method | 
| Property decorator | Class property | Add metadata or transformations | 
| Parameter decorator | Method param | Metadata for method parameters | 
📊 Setup for TypeScript
Enable decorators in your tsconfig.json:
{
  "compilerOptions": {
    "target": "ES6",
    "experimentalDecorators": true
  }
}For Babel, use: @babel/plugin-proposal-decorators
🧠 Summary Table
| Feature | Target | Purpose | 
|---|---|---|
| @log | Method | Logging/debugging | 
| @autobind | Method | Fix thisbinding | 
| @requireAdmin | Method | Authorization check | 
💭 Deeper Insight: Why Decorators?
Decorators provide a declarative way to apply cross-cutting concerns like:
- ✅ Logging
- 🔁 Memoization
- 🔐 Access control
- 💾 Caching
- ⌚ Rate limiting
Rather than adding repetitive boilerplate in every method, you write it once in a decorator and reuse it across your codebase.
This makes your business logic clean, reusable, and easy to read 💡
💬 Final Thoughts
Decorators help keep your code clean, elegant, and modular.
They're like invisible helpers that wrap around your logic — magical, but under your control 💫
Use them wisely and your code will thank you!
📖 Resources
Happy Decorating! 🌟