- TypeScript Tutorial
- TypeScript Home
- TypeScript Introduction
- TypeScript Setup
- TypeScript First Program
- TypeScript vs JavaScript
- TypeScript Data Types
- TypeScript Type Inference
- TypeScript Type Annotations
- TypeScript Interfaces
- TypeScript Enums
- TypeScript Type Aliases
- TypeScript Type Assertions
- TypeScript Variables
- TypeScript Functions
- TypeScript Functions
- TypeScript Optional Parameters
- TypeScript Default Parameters
- TypeScript Rest Parameters
- TypeScript Arrow Functions
- Classes and Objects
- Introduction to Classes
- Properties and Methods
- Access Modifiers
- Static Members
- Inheritance
- Abstract Classes
- Interfaces vs Classes
- Advanced Types
- TypeScript Union Types
- TypeScript Intersection Types
- TypeScript Literal Types
- TypeScript Nullable Types
- TypeScript Type Guards
- TypeScript Discriminated Unions
- TypeScript Index Signatures
- TypeScript Generics
- Introduction to Generics
- TypeScript Generic Functions
- TypeScript Generic Classes
- TypeScript Generic Constraints
- TypeScript Modules
- Introduction to Modules
- TypeScript Import and Export
- TypeScript Default Exports
- TypeScript Namespace
- Decorators
- Introduction to Decorators
- TypeScript Class Decorators
- TypeScript Method Decorators
- TypeScript Property Decorators
- TypeScript Parameter Decorators
- Configuration
- TypeScript tsconfig.json File
- TypeScript Compiler Options
- TypeScript Strict Mode
- TypeScript Watch Mode
TypeScript Method Decorators
Method decorators in TypeScript are a special kind of decorator that can be applied to a method within a class. They allow you to modify or extend the behavior of methods, such as logging, validation, or timing method execution, without changing the original method's code. Method decorators are applied to the prototype of the class and are executed whenever the method is called.
What is a Method Decorator?
A method decorator is a function that can be applied to a method and receives three arguments:
- The prototype of the class for instance methods or the constructor function for static methods.
- The name of the method.
- The descriptor of the method (which can be modified).
Method decorators are prefixed with the @
symbol and are applied directly above the method declaration.
Enabling Method Decorators in TypeScript
Before using decorators in TypeScript, you need to enable the experimentalDecorators
option in the tsconfig.json
file.
Example: Enabling Method Decorators
{
"compilerOptions": {
"experimentalDecorators": true
}
}
- The
experimentalDecorators
option must be set totrue
to use decorators, as they are not yet fully standardized in JavaScript.
Syntax of Method Decorators
A method decorator is defined as a function that receives three parameters:
- target: The prototype of the class or the constructor function of a static method.
- propertyKey: The name of the method being decorated.
- descriptor: The property descriptor for the method.
function MethodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(target, propertyKey, descriptor);
}
Applying Method Decorators
To apply a method decorator, place the decorator above the method you want to decorate.
Example: Applying a Simple Method Decorator
function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(`Method ${propertyKey} is called`);
}
class Example {
@Log
greet() {
console.log("Hello!");
}
}
const example = new Example();
example.greet();
// Output:
// Method greet is called
// Hello!
- The
@Log
decorator is applied to thegreet
method. Every time the method is called, the decorator logs a message.
Modifying the Method Behavior
You can use method decorators to modify the behavior of a method by altering its descriptor. The descriptor provides a way to modify the method's functionality, such as replacing it with a new function.
Example: Modifying the Method
function ChangeMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Method ${propertyKey} is called with arguments:`, args);
return originalMethod.apply(this, args);
};
}
class Example {
@ChangeMethod
greet(name: string) {
console.log(`Hello, ${name}!`);
}
}
const example = new Example();
example.greet('John');
// Output:
// Method greet is called with arguments: [ 'John' ]
// Hello, John!
- The
ChangeMethod
decorator wraps the originalgreet
method and logs the arguments passed to it before calling the original method.
Accessing and Modifying Method Properties
Method decorators can access and modify the method's descriptor. The PropertyDescriptor
object provides several properties, such as value
(the method), writable
(whether the method is writable), enumerable
, and configurable
.
Example: Read-Only Method
function ReadOnly(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.writable = false;
}
class Example {
@ReadOnly
greet() {
console.log("Hello!");
}
}
const example = new Example();
example.greet(); // Output: Hello!
example.greet = () => console.log("Goodbye!");
example.greet(); // Error: Cannot assign to read only property 'greet' of object.
- The
ReadOnly
decorator sets thewritable
property of the method descriptor tofalse
, making the method non-overridable.
Method Decorators with Parameters
You can also create method decorators that accept parameters, using a decorator factory. This allows you to pass additional values to the decorator for customization.
Example: Method Decorator with Parameters
function LogExecutionTime(message: string) {
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
const start = Date.now();
const result = originalMethod.apply(this, args);
const end = Date.now();
console.log(`${message}: ${propertyKey} executed in ${end - start}ms`);
return result;
};
};
}
class Example {
@LogExecutionTime("Execution time")
slowMethod() {
for (let i = 0; i < 1e6; i++) {} // Simulate delay
console.log("Slow method executed");
}
}
const example = new Example();
example.slowMethod();
// Output:
// Execution time: slowMethod executed in [time]ms
// Slow method executed
- In this example, the
LogExecutionTime
decorator factory allows us to pass a custom message and measures the execution time of the method.
Using Method Decorators for Validation
Method decorators can also be used for validation purposes, such as checking if the arguments passed to a method meet certain criteria.
Example: Method Decorator for Validation
function ValidateArgs(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
if (args.some(arg => arg <= 0)) {
throw new Error("Arguments must be greater than zero.");
}
return originalMethod.apply(this, args);
};
}
class Example {
@ValidateArgs
setAge(age: number) {
console.log(`Age set to ${age}`);
}
}
const example = new Example();
example.setAge(25); // Output: Age set to 25
example.setAge(-5); // Throws Error: Arguments must be greater than zero.
- The
ValidateArgs
decorator checks if any of the arguments are less than or equal to zero before executing the method, throwing an error if validation fails.
Summary
- Method decorators in TypeScript are used to modify or extend the behavior of a method within a class.
- They are applied directly above the method declaration and allow you to modify method descriptors, log method execution, or add new behavior.
- Method decorators can be used to wrap methods, change their behavior, and perform tasks like logging, validation, and performance tracking.
- They are an important part of TypeScript's decorator feature, enabling powerful metaprogramming capabilities.