Decorators

The 150 Endpoints That Needed Logging

Tuesday morning standup. Product manager: "We need request logging on all API endpoints. For debugging and analytics."

I looked at our codebase: 150 REST API endpoints across 23 controllers. Manual logging would mean:

// Before - Manual logging everywhere
class UserController {
  async getUser(id: string) {
    console.log(`[${new Date().toISOString()}] GET /users/${id}`);
    const startTime = Date.now();
    
    try {
      const user = await this.userService.findById(id);
      console.log(`[${new Date().toISOString()}] GET /users/${id} - ${Date.now() - startTime}ms`);
      return user;
    } catch (error) {
      console.error(`[${new Date().toISOString()}] GET /users/${id} - ERROR:`, error);
      throw error;
    }
  }
  
  // ... repeat for 149 more endpoints!
}

Estimated time: 2 weeks of tedious copy-paste. High risk of inconsistency and bugs.

Then I discovered decorators:

Result: Added logging to 150 endpoints in 3 hours. Consistent. Maintainable. DRY.

This article covers TypeScript decorators - the meta-programming feature that saves you from repetitive boilerplate.


Enabling Decorators

Decorators are experimental. Enable in tsconfig.json:


Class Decorators

Modify or replace class definitions.

Basic Class Decorator

Adding Properties

Sealed Class


Method Decorators

Modify method behavior.

Basic Method Decorator

Measure Performance

Memoization Decorator


Property Decorators

Modify property definitions.

Basic Property Decorator


Parameter Decorators

Mark parameters for special handling.

Basic Parameter Decorator


Decorator Factories

Create decorators with custom parameters.

Parameterized Decorator

Retry Decorator


Decorator Composition

Multiple decorators on one target.

Execution Order

Execution order:

  1. Factories: top to bottom

  2. Decorators: bottom to top


Real-World Patterns

1. Authorization Decorator

2. Validation Decorator

3. Caching Decorator


Common Mistakes

1. Forgetting to Enable

2. Arrow Function Methods

3. Not Returning Descriptor


Your Challenge

Build a request timing and logging system with decorators:


Key Takeaways

  1. Decorators - meta-programming for classes and methods

  2. Enable in tsconfig - experimentalDecorators: true

  3. Method decorators - modify behavior without changing code

  4. Decorator factories - parameterized decorators

  5. Composition - stack multiple decorators

  6. Real use cases - logging, caching, auth, validation

  7. Execution order - bottom to top

  8. Return descriptor - don't forget!


What I Learned

Adding logging to 150 endpoints manually would have taken 2 weeks. Error-prone. Inconsistent. Unmaintainable.

One decorator took 3 hours:

Decorators turn cross-cutting concerns (logging, auth, validation, caching) into reusable, composable annotations.

Before decorators, every endpoint had logging boilerplate. After decorators, logging is declared once, applied everywhere.

Decorators are DRY on steroids. They let you write the behavior once and sprinkle it where needed.

The lesson: Repetitive code is a signal. If you're copy-pasting the same pattern, you need abstraction. Decorators are that abstraction.

Make your code declarative. Let decorators handle the repetition.


Next: TypeScript with Frameworks

In the next article, we'll explore TypeScript with React, Express, and other frameworks. You'll learn how proper typing caught a critical React state bug before users noticed.

Last updated