TypeScript decorators are a powerful feature that allow you to add metadata and modify the behavior of classes, methods, properties, and parameters. Decorators provide a way to enhance and extend the functionality of your TypeScript code by applying annotations and transformations at compile-time. In this article, we’ll explore how to use TypeScript decorators and demonstrate their various applications.
Understanding TypeScript Decorators
Decorators in TypeScript are functions that are prefixed with the @
symbol and are applied to target declarations using the decorator syntax. They can be used to modify the behavior or add metadata to classes, methods, properties, or parameters.
To use a decorator, you simply place it before the declaration it is applied to. The decorator function is invoked with different arguments depending on the context it is used in. It can modify the behavior of the target declaration or attach additional properties or metadata to it.
TypeScript provides built-in decorators such as @classDecorator
, @methodDecorator
, @propertyDecorator
, and @parameterDecorator
, along with the ability to create custom decorators.
Using Class Decorators
Class decorators are applied to classes and can modify or augment their behavior. They receive the class constructor as their only parameter and can return a new constructor or extend the existing one. Here’s an example of a class decorator:
function logged(target: Function) {
console.log(`Class ${target.name} is decorated.`);
}
@logged
class MyClass {
// Class implementation
}
In this example, the @logged
decorator is applied to the MyClass
declaration. The decorator function logs a message indicating that the class is decorated. When the code is executed, the message “Class MyClass is decorated.” is printed to the console.
Class decorators can be useful for logging, dependency injection, applying mixins, or modifying class behavior.
Using Method Decorators
Method decorators are applied to methods within a class. They receive three parameters: the target object (prototype), the property key (method name), and the property descriptor. Method decorators can modify the behavior of the method or add additional functionality. Here’s an example:
function measure(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Method ${key} is called with arguments: ${args}`);
const startTime = Date.now();
const result = originalMethod.apply(this, args);
const endTime = Date.now();
console.log(`Method ${key} execution time: ${endTime - startTime}ms`);
return result;
}
}
class Calculator {
@measure
add(a: number, b: number): number {
return a + b;
}
}
In this example, the @measure
decorator is applied to the add
method of the Calculator
class. The decorator modifies the method behavior by logging the method call with its arguments, measuring the execution time, and printing it to the console.
Method decorators can be used for logging, performance monitoring, access control, or method augmentation.
Using Property Decorators
Property decorators are applied to class properties. They receive two parameters: the target object (prototype) and the property key. Property decorators can be used to observe, modify, or add additional behavior to class properties. Here’s an example:
function uppercase(target: any, key: string) {
let value = target[key];
const getter = function () {
return value;
};
const setter = function (newVal: string) {
value = newVal.toUpperCase();
};
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
}
class Person {
@uppercase
name: string;
constructor(name: string) {
this.name = name;
}
}
const person = new Person("John Doe");
console.log(person.name); // Output: "JOHN DOE"
In this example, the @uppercase
decorator is applied to the name
property of the Person
class. The decorator converts the assigned value to uppercase using getters and setters defined in the decorator function.
Property decorators can be useful for value transformations, validation, data binding, or accessing properties.
Using Parameter Decorators
Parameter decorators are applied to the parameters of a method or constructor within a class. They receive three parameters: the target object (prototype) or constructor, the property key (method name or constructor), and the parameter index. Parameter decorators can modify or provide additional information about method arguments. Here’s an example:
function logParameter(target: any, key: string, index: number) {
console.log(`Method ${key} parameter at index ${index} is decorated.`);
}
class Greeter {
greet(@logParameter name: string) {
console.log(`Hello, ${name}!`);
}
}
const greeter = new Greeter();
greeter.greet("John"); // Output: "Hello, John!"
In this example, the @logParameter
decorator is applied to the name
parameter of the greet
method in the Greeter
class. The decorator logs a message indicating that the parameter is decorated.
Parameter decorators can be useful for logging, validation, dependency injection, or metadata retrieval.
Conclusion
TypeScript decorators are a powerful feature that allows you to add metadata and modify the behavior of classes, methods, properties, and parameters. They provide a way to extend and enhance the functionality of your TypeScript code at compile-time. By using decorators, you can add logging, modify method behavior, transform property values, or provide additional information about method arguments. Understanding and utilizing decorators can greatly enhance the expressiveness and extensibility of your TypeScript applications. Experiment with decorators and explore their various applications to unleash the full potential of TypeScript in your projects.
There we have how to Use TypeScript Decorators, if you want more like this be sure to check out some of my other posts!