← Back to TypeScript Course | Chapter 10: Decorators | Lesson 3 of 7

Method Decorators

A method decorator receives the original method and a ClassMethodDecoratorContext. It can inspect the method, register initialization logic, or return a replacement method with added behavior.

Basic Method Decorator

A method decorator is a function applied just above a class method that receives the target class, method name, and property descriptor, letting it observe, modify, or replace that method's definition before the class is even instantiated.

Example: Basic Method Decorator

typescript
function bound(target: any, context: ClassMethodDecoratorContext) {
  console.log("Decorating method:", String(context.name));
}
class Widget {
  @bound
  render() {
    return "rendered";
  }
}
new Widget().render();

Logging Method Calls

Wrapping the original method inside the decorator lets you log every call's arguments and return value without touching the method's own body, which keeps cross-cutting concerns like logging separate from business logic.

Example: Logging Method Calls

typescript
function logCall(target: any, context: ClassMethodDecoratorContext) {
  return function (this: any, ...args: any[]) {
    console.log(`Calling ${String(context.name)} with`, args);
    const result = target.call(this, ...args);
    console.log("Returned", result);
    return result;
  };
}
class Calculator {
  @logCall
  add(a: number, b: number) {
    return a + b;
  }
}
new Calculator().add(2, 3);

Validating Method Arguments

By intercepting the descriptor's value function, a decorator can inspect incoming arguments and throw before the real method runs, giving you reusable validation instead of repeating checks at the top of every method.

Example: Validating Method Arguments

typescript
function positiveOnly(target: any, context: ClassMethodDecoratorContext) {
  return function (this: any, ...args: any[]) {
    if (args.some((a) => typeof a === "number" && a < 0)) {
      throw new Error("Arguments must be positive");
    }
    return target.call(this, ...args);
  };
}
class Account {
  @positiveOnly
  deposit(amount: number) {
    return amount;
  }
}
console.log(new Account().deposit(100));

Method Initializers

Some decorators go further and replace the method entirely with a new function that calls the original internally, which is how patterns like memoization or automatic retries get bolted onto existing methods.

Example: Method Initializers

typescript
function once(target: any, context: ClassMethodDecoratorContext) {
  let called = false;
  let result: any;
  return function (this: any, ...args: any[]) {
    if (!called) {
      result = target.call(this, ...args);
      called = true;
    }
    return result;
  };
}
class Loader {
  @once
  load() {
    console.log("Loading...");
    return "data";
  }
}
const loader = new Loader();
loader.load();
loader.load();

Method Decorator Factories

A decorator factory is a function that returns a method decorator, so you can pass configuration (like a log level or a retry count) into the decorator itself rather than hardcoding behavior into one fixed implementation.

Example: Method Decorator Factories

typescript
function retry(times: number) {
  return function (target: any, context: ClassMethodDecoratorContext) {
    return function (this: any, ...args: any[]) {
      console.log(`Configured to retry ${times} times`);
      return target.call(this, ...args);
    };
  };
}
class Api {
  @retry(3)
  fetchData() {
    return "data";
  }
}
new Api().fetchData();
🔒

Chapter Quiz — Complete all 7 topics to unlock

0/7 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.