TypeScript

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

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.

Text
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:

Text
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:

Text
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.