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
Person
with propertiesfirstName
andlastName
. - Add a method
getFullName
that returns the full name of the person. - Create a decorator
logMethod
that logs the method name and arguments whenevergetFullName
is 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
logMethod
decorator logs the method name and arguments whenever thegetFullName
method is called. - The
Person
class has propertiesfirstName
andlastName
, and a methodgetFullName
that returns the full name. - When
getFullName
is 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