Typescript decorators
Created By: chatGPT
TypeScript decorators are a powerful feature that allows you to modify the behavior of classes, methods, accessors, properties, or parameters. They are essentially functions that can be attached to a target to modify its behavior in a reusable way. Decorators work well with object-oriented programming and can help in augmenting existing code without modifying it directly.
// Basic decorator definition
function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling ${propertyKey} with`, args);
return originalMethod.apply(this, args);
};
}
To use decorators, enable the experimental metadata and decorator support in your
tsconfig.json
file by setting experimentalDecorators
and emitDecoratorMetadata
to true
.{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
Once decorators are enabled, you can apply them to classes or methods. For example, below is a simple use of a class decorator that counts the number of instances created.
let instanceCount = 0;
function CountInstances<T extends { new(...args: any[]): {} }>(constructor: T) {
return class extends constructor {
constructor(...args: any[]) {
super(...args);
instanceCount++;
console.log(`Instances created: ${instanceCount}`);
}
};
}
@CountInstances
class MyClass {
constructor(public name: string) {}
}
const obj1 = new MyClass('First Instance');
const obj2 = new MyClass('Second Instance');
Method decorators can enhance or modify specific methods. In the previous example, the
Log
decorator can be applied to a method to log its calls. Below is how you would use it.class Example {
@Log
sayHello(name: string) {
return `Hello, ${name}!`;
}
}
const example = new Example();
console.log(example.sayHello('World'));
Additionally, you can also create property decorators. Below is an example that validates if the value assigned to the property is a non-empty string.
function IsNonEmptyString(target: any, propertyKey: string) {
let value: string;
const getter = () => value;
const setter = (newValue: string) => {
if (!newValue) {
console.error(`${propertyKey} cannot be empty!`);
} else {
value = newValue;
}
};
Object.defineProperty(target, propertyKey, { get: getter, set: setter });
}
class User {
@IsNonEmptyString
name: string = '';
}
const user = new User();
user.name = ''; // Will log an error
user.name = 'John'; // Will set the value