Method Decorators
In this page:
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
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
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
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
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
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: