Step 11 – Decorators in TypeScript

Decorators are a powerful feature in TypeScript that allow you to add metadata or behavior to classes, methods, properties, and other declarations in your code. Decorators use a special syntax of the @ symbol followed by a function name, which is applied to the target declaration. When the decorator is applied, the function is executed with information about the target, and can modify its behavior or properties.

Defining a decorator

To define a decorator, you simply create a function that takes the target as an argument, and returns either the target or a new object that replaces it. Here’s a simple example of a decorator that logs a message when a method is called:

function log(target: any, key: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`Calling method ${key} with arguments:`, ...args);
    const result = originalMethod.apply(this, args);
    console.log(`Method ${key} returned:`, result);
    return result;
  };
  return descriptor;
}

In this example, the log function takes three arguments: target, which is the class or object that the method belongs to, key, which is the name of the method, and descriptor, which contains information about the method. The function then replaces the original method with a new function that logs a message before and after calling the original method.

Applying a decorator

To apply a decorator, you simply add the @ symbol followed by the decorator name to the declaration of the target. For example, to apply the log decorator to a method called myMethod in a class called MyClass, you would write:

class MyClass {
  @log
  myMethod(arg1: string, arg2: number) {
    // ...
  }
}

When you call myMethod, the decorator will be applied and the log messages will be printed to the console.

Decorator factories

You can also define decorator factories, which are functions that return a decorator function. Decorator factories allow you to pass arguments to the decorator, which can then be used to modify the behavior of the decorator. Here’s an example of a decorator factory that logs a message with a custom prefix:

function logWithPrefix(prefix: string) {
  return function (target: any, key: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
      console.log(`[${prefix}] Calling method ${key} with arguments:`, ...args);
      const result = originalMethod.apply(this, args);
      console.log(`[${prefix}] Method ${key} returned:`, result);
      return result;
    };
    return descriptor;
  };
}

You can use this decorator factory to create a new decorator with a specific prefix, like this:

class MyClass {
  @logWithPrefix('DEBUG')
  myMethod(arg1: string, arg2: number) {
    // ...
  }
}

Now when you call myMethod, the log messages will include the prefix DEBUG:

[DEBUG] Calling method myMethod with arguments: arg1, 42
[DEBUG] Method myMethod returned: result
Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.