
Play Store Application link – Java to TypeScript in 14 Steps – App on Google Play
Decorators in TypeScript are a way to add extra behavior to classes, methods, properties, or other declarations. They’re similar to annotations in Java, providing a powerful way to modify or enhance the functionality of your code.
Defining a Decorator
A decorator is essentially a function that takes certain arguments and modifies the behavior of the target it decorates. The decorator function receives information about the target (such as a class or method) and can return either the target itself or a modified version.
Java Comparison:
In Java, you might use annotations and reflection to achieve similar functionality:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
}
public class MyClass {
@Log
public void myMethod(String arg1, int arg2) {
// ...
}
}
In this Java example, @Log
is an annotation that could be processed via reflection to add behavior, similar to how decorators work in TypeScript.
TypeScript Example:
Here’s how you define a simple decorator that logs method calls:
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;
}
This log
decorator wraps a method, logging its arguments and return value.
Applying a Decorator
To use a decorator, you apply it to a class method by prefixing it with the @
symbol. The decorator function runs when the method is defined.
TypeScript Example:
class MyClass {
@log
myMethod(arg1: string, arg2: number) {
// Method implementation
return `Processed ${arg1} and ${arg2}`;
}
}
When myMethod
is called, it will execute with the logging behavior defined by the log
decorator.
Decorator Factories
Decorator factories are functions that return decorators. They let you pass arguments to decorators, providing more flexibility.
Java Comparison:
In Java, you might use a factory method to create different instances of annotations or to handle different scenarios.
TypeScript Example:
Here’s a decorator factory that logs messages 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;
};
}
Using the Decorator Factory:
class MyClass {
@logWithPrefix('DEBUG')
myMethod(arg1: string, arg2: number) {
// Method implementation
return `Processed ${arg1} and ${arg2}`;
}
}
Now, calling myMethod
will include the custom prefix DEBUG
in the log messages.
Conclusion
Decorators in TypeScript offer a powerful way to enhance classes and methods with additional behavior. They are comparable to Java annotations and can be used for logging, validation, and other cross-cutting concerns. By defining simple decorators or more advanced decorator factories, you can add reusable functionality across your TypeScript codebase, improving maintainability and consistency.