Decorators are a special kind of declaration that can be attached to a class, method, accessor, property, or parameter. Decorators are a stage 2 proposal for JavaScript and are available as an experimental feature in TypeScript. They provide a way to add both annotations and a meta-programming syntax for class declarations and members.
Key Concepts
- Decorator Factories: Functions that return the decorator function.
- Decorator Composition: Multiple decorators can be applied to a single declaration.
- Decorator Evaluation: Decorators are evaluated in a specific order.
Types of Decorators
- Class Decorators: Applied to a class constructor.
- Method Decorators: Applied to a method.
- Accessor Decorators: Applied to a getter or setter.
- Property Decorators: Applied to a property.
- Parameter Decorators: Applied to a method parameter.
Class Decorators
A class decorator is a function that takes a class constructor as an argument and returns either a new constructor or the same constructor.
Example
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return `Hello, ${this.greeting}`;
}
}In this example, the @sealed decorator seals the Greeter class, preventing new properties from being added to it.
Method Decorators
A method decorator is a function that takes three arguments: the target (either the constructor function of the class for a static method or the prototype of the class for an instance method), the name of the method, and the property descriptor.
Example
function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@enumerable(false)
greet() {
return `Hello, ${this.greeting}`;
}
}In this example, the @enumerable(false) decorator sets the enumerable property of the greet method's descriptor to false.
Property Decorators
A property decorator is a function that takes two arguments: the target (either the constructor function of the class for a static property or the prototype of the class for an instance property) and the name of the property.
Example
function format(formatString: string) {
return function (target: any, propertyKey: string) {
let value: string;
const getter = function () {
return value;
};
const setter = function (newVal: string) {
value = `${formatString} ${newVal}`;
};
Object.defineProperty(target, propertyKey, {
get: getter,
set: setter,
enumerable: true,
configurable: true,
});
};
}
class Greeter {
@format('Hello')
greeting: string;
constructor(message: string) {
this.greeting = message;
}
}In this example, the @format('Hello') decorator modifies the greeting property to prepend "Hello" to any value assigned to it.
Practical Exercise
Task
- Create a class
Personwith propertiesfirstNameandlastName. - Add a method
getFullNamethat returns the full name of the person. - Create a decorator
logMethodthat logs the method name and arguments whenevergetFullNameis called.
Solution
function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Method ${propertyKey} called with args: ${JSON.stringify(args)}`);
return originalMethod.apply(this, args);
};
return descriptor;
}
class Person {
firstName: string;
lastName: string;
constructor(firstName: string, lastName: string) {
this.firstName = firstName;
this.lastName = lastName;
}
@logMethod
getFullName() {
return `${this.firstName} ${this.lastName}`;
}
}
const person = new Person('John', 'Doe');
console.log(person.getFullName());Explanation
- The
logMethoddecorator logs the method name and arguments whenever thegetFullNamemethod is called. - The
Personclass has propertiesfirstNameandlastName, and a methodgetFullNamethat returns the full name. - When
getFullNameis called, the decorator logs the method name and arguments, then calls the original method.
Summary
- Decorators provide a way to add annotations and meta-programming syntax to class declarations and members.
- There are different types of decorators: class, method, accessor, property, and parameter decorators.
- Decorators can be composed and are evaluated in a specific order.
- Practical examples and exercises help reinforce the concepts learned.
In the next section, we will explore asynchronous programming in TypeScript, starting with Promises.
TypeScript Course
Module 1: Introduction to TypeScript
- What is TypeScript?
- Setting Up the TypeScript Environment
- Basic Types
- Type Annotations
- Compiling TypeScript
Module 2: Working with Types
Module 3: Advanced Types
Module 4: Functions and Modules
Module 5: Asynchronous Programming
Module 6: Tooling and Best Practices
- Linting and Formatting
- Testing TypeScript Code
- TypeScript with Webpack
- TypeScript with React
- Best Practices
