DEV Community

Dharan Ganesan
Dharan Ganesan

Posted on

Day 44: Decorators

In this article, we'll take a dive into decorators in TypeScript, explore their types, and provide practical examples to help you harness their full potential.

What Are Decorators? 🎨

At their core, decorators are simply functions that are applied to classes, methods, properties, or parameters using the @ symbol. They can be used for various purposes, including:

  1. Logging and debugging: Adding logging statements before and after method execution.
  2. Validation: Checking the validity of inputs or outputs.
  3. Authorization: Controlling access to certain methods or routes.
  4. Memoization: Caching the results of expensive operations.
  5. Dependency Injection: Automatically injecting dependencies into classes.
  6. Metadata Collection: Storing additional information about classes or properties.

Class Decorators 🏛️

Class decorators are applied to classes. They receive the class constructor as their only parameter and can be used to modify the class or add metadata to it.

function MyDecorator(target: Function) { console.log('Class decorator called on', target); } @MyDecorator class MyClass { constructor() { console.log('MyClass constructor'); } } // Output: // Class decorator called on [Function: MyClass] // MyClass constructor 
Enter fullscreen mode Exit fullscreen mode

Method Decorators 🛠️

Method decorators are applied to methods within a class. They receive three parameters: the target class prototype, the method name, and a property descriptor.

function LogMethod(target: Object, key: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { console.log(`Calling ${key} with arguments: ${args}`); const result = originalMethod.apply(this, args); console.log(`${key} returned: ${result}`); return result; }; return descriptor; } class Calculator { @LogMethod add(a: number, b: number): number { return a + b; } } const calc = new Calculator(); calc.add(2, 3); // Output: // Calling add with arguments: 2,3 // add returned: 5 
Enter fullscreen mode Exit fullscreen mode

Property Decorators 🏠

Property decorators are used to modify properties within a class. They receive two parameters: the target class prototype and the property name.

function Validate(target: any, key: string) { let value = target[key]; const getter = () => value; const setter = (newValue: any) => { if (typeof newValue !== 'number' || newValue < 0) { throw new Error('Invalid value'); } value = newValue; }; Object.defineProperty(target, key, { get: getter, set: setter, }); } class Product { @Validate price: number; constructor(price: number) { this.price = price; } } const product = new Product(50); product.price = -10; // Throws an error // Output: // Error: Invalid value 
Enter fullscreen mode Exit fullscreen mode

Parameter Decorators 🎯

Parameter decorators are applied to parameters of methods within a class. They receive three parameters: the target class prototype, the method name, and the index of the parameter.

const Injectable = (): ParameterDecorator => { return (target: any, key: string | symbol, index: number) => { // Register the dependency injection here console.log(`Injecting parameter at index ${index} in method ${key}`); }; }; class UserService { constructor(private readonly logger: Logger) {} @Injectable() log(message: string) { this.logger.log(message); } } const logger = new Logger(); const userService = new UserService(logger); userService.log('Hello, Decorators!'); // Output: // Injecting parameter at index 0 in method log // Hello, Decorators! 
Enter fullscreen mode Exit fullscreen mode

Top comments (0)