Decorators in TypeScript: Code Reusability
I had a class with two methods. Both needed logging. So I copy-pasted console.log calls into each one.
24 Apr 2024

I had a class with two methods. Both needed logging. So I copy-pasted console.log calls into each one.
class User {
constructor(private name: string, private age: number) {}
greet() {
console.log('start: greet')
console.log(`Hello, my name is ${this.name}.`);
console.log('end: greet')
}
printAge() {
console.log('start: printAge')
console.log(`I am ${this.age} years old`);
console.log('end: printAge')
}
}
const user = new User("Ron", 25);
user.greet();
user.printAge();
Two methods. Fine. Ten methods? That's a maintenance nightmare.
Decorators fix this. A decorator is a function you attach to a method (or class, property, parameter). It wraps behavior around the original without touching the original.
Here's a logger decorator:
function logger(originalMethod: any, _context: any) {
function replacementMethod(this: any, ...args: any[]) {
console.log("start:", originalMethod.name);
const result = originalMethod.call(this, ...args);
console.log("end:", originalMethod.name);
return result;
}
return replacementMethod;
}
Now the class becomes clean:
class User {
constructor(private name: string, private age: number) {}
@logger
greet() {
console.log(`Hello, my name is ${this.name}.`);
}
@logger
printAge() {
console.log(`I am ${this.age} years old`);
}
}
const user = new User("Ron", 25);
user.greet();
user.printAge();
One @logger tag. No duplicated console.log calls. Add a new method? Slap @logger on it. Done.
The trade-off
Decorators make cross-cutting concerns (logging, caching, validation) clean and reusable. But they hide behavior. Someone reading greet() won't see the logging unless they know to check the decorator. That's a readability cost.
Use them when the pattern is genuinely repeated. Don't use them to be clever.