DEV Community

Cover image for All You Need to Know about Decorators in TypeScript
Arul Valan Anto S
Arul Valan Anto S

Posted on

All You Need to Know about Decorators in TypeScript

This article will concentrate on Decorators, one of the features in TypeScript. We will delve into its details and explore its functionality using real-life examples. Let’s go!

Decorators are a feature in TypeScript that allows you to add metadata and modify the behavior of classes, methods, properties, and parameters at compile time. Decorators are functions that are prefixed with the @ symbol.

Note: decorators are an experimental feature in TypeScript. To enable decorators in your TypeScript project, you must enable the "experimentalDecorators" compiler option in your tsconfig.json file.

// tsconfig.json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    // other compiler options...
  }
}
Enter fullscreen mode Exit fullscreen mode

Okay. Let’s see a simple example.

function uppercase(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    const result = originalMethod.apply(this, args);

    if (typeof result === "string") {
       return result.toUpperCase();
    }

    return result;
  };

  return descriptor;
}

class User {
  private name: string;

  constructor(name) {
    this.name = name;
  }

  // In this code, the uppercase decorator is applied to the getName method 
  // of the User class using the @uppercase syntax. 
  // This means that whenever the getName method is called, 
  // the uppercase decorator function will be invoked.
  @uppercase
  getName() {
    return this.name
  }
}

const user = new User("Arul Valan Anto");
console.log(user.getName());

// 🚀 output
// ARUL VALAN ANTO
Enter fullscreen mode Exit fullscreen mode

This is the decorator function named uppercase. It takes three parameters:

  • target: any: The target object or class on which the decorator is applied.
  • propertyKey: string: The name of the property or method being decorated.
  • descriptor: PropertyDescriptor: The property descriptor of the decorated property or method.

Use cases

  1. Logging and debugging: You can use decorators to add logging statements or debug information around methods or functions, helping you track the execution flow and inspect values during development.

  2. Validation and data transformation: Decorators can validate the input parameters of methods or ensure the correctness of data properties.

  3. Authorization and access control: Decorators can check user permissions or apply access control rules to methods or classes.

  4. Dependency injection: Decorators can be used in conjunction with dependency injection frameworks to automatically inject dependencies into classes. This practice is commonly observed in various places, notably within the Angular framework.

  5. API documentation: Decorators can be used for generating API documentation and configuring serialization/deserialization processes.

Example

Suppose you have a Node.js server application that handles various API routes, and you want to measure the execution time of certain methods to monitor performance. You can use decorators to create a reusable method timing decorator that logs the execution time of methods. Here’s an example implementation:

// 👇 Decorator to measure method execution time
function measureTime(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = async function (...args: any[]) {
    const start = Date.now();
    const result = await originalMethod.apply(this, args);
    const end = Date.now();
    const executionTime = end - start;

    console.log(`${propertyKey} took ${executionTime}ms`);

    return result;
  };

  return descriptor;
}

class UserController {
  // 👇 Add metadata like this 
  @measureTime
  static async getUser(userId: string) {
    await new Promise((resolve) => setTimeout(resolve, 2000));
    return { id: userId, name: 'John Doe' };
  }
}

// Express route handler
app.get('/users/:id', async (req, res) => {
  const userId = req.params.id;
  const user = await UserController.getUser(userId);
  res.json(user);
});

Enter fullscreen mode Exit fullscreen mode

I have only scratched the surface of decorators in TypeScript with a few mentioned use cases, but there’s so much more to explore! Feel free to dive into the rich functionality of TypeScript and expand your toolkit. Today, I have equipped you with a valuable addition to your TypeScript toolbox.

I genuinely believe this article will be a helpful resource for all of you!

Stay curious; keep coding!

Top comments (3)

Collapse
 
knopkem profile image
Michael Knopke

Decorators are not in Experimental Stage anymore since TS 5

Collapse
 
arulvalananto profile image
Arul Valan Anto S

Gotcha

Collapse
 
teaganga profile image
teaganga

I primary use js, but this feature sounds really nice, could reduce the complexity of the code. I tried to implement the decorator pattern in js, as a function, to make use of js language features.

P.S. I would be nice to highlight the code by using

typescript instead of

when starting a code block.