What Are Decorators in TypeScript? A Beginner-Friendly Guide

Profile picture of Bhavik Bamania
Bhavik Bamania
·4 min read
What Are Decorators in TypeScript? A Beginner's Guide
What Are Decorators in TypeScript? A Beginner's Guide

Have you ever wished for a magic wand in your code that could automatically enhance or modify the behavior of your functions, classes, or properties without changing their original structure? Well, that’s what decorators in TypeScript do! Decorators are a special kind of declaration that can be attached to classes, methods, accessors, properties, or parameters to add extra functionality.

In this article, we’ll break down the concept of decorators in TypeScript and explore how they work in simple, digestible terms. Whether you’re new to TypeScript or just want to deepen your understanding, this guide is for you!

Feeling Lost?

If you are feeling alienated and feels that you are in the wrong territory, you can make yourself comfortable with Typescript, and by reading previous articles about typescript:

First-Class Decorators: The Basics

In TypeScript, a first-class decorator is a function that can be attached to a class, method, or property. Think of it as a way to wrap or modify what a function, class, or property does, without changing the code inside them.

Here’s a simple example:

function simpleDecorator(target: any) {
 console.log("Decorator is applied!");
}
@simpleDecorator
class MyClass {
 // This class is now decorated!
}

When `MyClass` is defined, the `simpleDecorator` function will automatically run, printing “Decorator is applied!” to the console. In essence, decorators allow you to inject additional behavior into your code in a clean, readable way.

Working with Decorator Factories

Sometimes, you need more flexibility with your decorators — like passing arguments to customize their behavior. This is where decorator factories come in. A decorator factory is simply a function that returns a decorator.

function decoratorFactory(message: string) {
 return function(target: any) {
 console.log(message);
 };
}
@decoratorFactory("Hello, TypeScript!")
class AnotherClass {
 // The message is customized through the decorator factory
}

In this example, `decoratorFactory` returns a decorator that prints a custom message when applied. This is incredibly useful when you want to reuse a decorator with different configurations.

Adding Multiple Decorators

What if you want to apply multiple decorators to a single class or method? TypeScript makes this easy. You can stack decorators on top of each other, and they will be executed in a specific order (from bottom to top).

function firstDecorator(target: any) {
 console.log("First decorator applied");
}
function secondDecorator(target: any) {
 console.log("Second decorator applied");
}
@firstDecorator
@secondDecorator
class MultipleDecoratorsClass {
 // Both decorators are applied in sequence
}

When `MultipleDecoratorsClass` is defined, “Second decorator applied” will be printed first, followed by “First decorator applied.” Understanding the order of execution is key when combining multiple decorators.

Diving into Property Decorators

Property decorators are special functions applied to class properties. They let you observe and modify properties, even before the properties are fully initialized.

function logProperty(target: any, propertyKey: string) {
 console.log(`Property ${propertyKey} has been defined.`);
}
class PropertyDecoratorClass {
 @logProperty
 myProperty: string;
constructor() {
 this.myProperty = "Hello!";
 }
}

Here, `logProperty` logs a message whenever `myProperty` is defined in `PropertyDecoratorClass`. Property decorators are great for tasks like validation or logging, making them powerful tools for managing class properties.

Accessor and Parameter Decorators

Accessor decorators are applied to getters or setters of a property, allowing you to modify how the value is retrieved or set.

function logAccess(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
 const originalMethod = descriptor.get;
 descriptor.get = function() {
 console.log(`Getting value of ${propertyKey}`);
 return originalMethod?.apply(this);
 };
}
class AccessorDecoratorClass {
 private _name: string = "TypeScript";
@logAccess
 get name() {
 return this._name;
 }
}

In this example, `logAccess` decorates the getter for `name`, logging a message whenever the property is accessed.

Parameter decorators are less common but equally powerful. They allow you to decorate and modify parameters passed into a method.

function logParameter(target: any, propertyKey: string, parameterIndex: number) {
 console.log(`Parameter at index ${parameterIndex} in ${propertyKey} is being decorated`);
}
class ParameterDecoratorClass {
 myMethod(@logParameter param: string) {
 console.log(param);
 }
}

The `logParameter` decorator logs information about the method’s parameter, giving you control over how arguments are handled.

When Do Decorators Execute?

Understanding when decorators execute is crucial. Decorators are applied at runtime, but they execute when the class is defined, not when an instance of the class is created.

For example, if you define a class with decorators, the decorators will run as soon as the class definition is processed, which is typically when the script is loaded.

Decorators Return Types

Decorators can modify or replace what they decorate. The return type of a decorator depends on what it’s applied to:

- Class Decorators: They can replace the class constructor or simply modify the class.
- Method and Accessor Decorators: They can replace the method or accessor’s descriptor.
- Property Decorators: They typically don’t return anything, as they modify the property directly.
- Parameter Decorators: They don’t have a return value but can modify how parameters are handled.

Conclusion

Decorators in TypeScript are powerful tools that can enhance your code by adding extra layers of functionality in a clean, modular way. From first-class decorators to more complex use cases like accessor and parameter decorators, understanding how and when to use them can significantly improve your codebase.

Whether you’re a seasoned developer or just getting started with TypeScript, decorators offer a flexible and powerful way to manage and extend the behavior of your code. Happy coding!

Author of Bhavik Bamania

Written by

Bhavik Bamania