Decorators
Class Decorators
We can create class decorator using @Function name and pass the function a constructor.
function Component(constructor: Function) {
// This function called once
console.log("Component decorator called");
constructor.prototype.userId = Date.now();
constructor.prototype.insertInDom = () => {
console.log("Inserting dom component in dom ");
};
}
@Component
class ProfileComponent {
// Every instance of this class has the (userId) amd (insertInDom)
}
Decorators With Parameters
we can make the constructor function anonymous and pass argument from its parent function. Also we can define type for the type of the argument . We can have multiple decorators
type ComponentOptions = {
selector: string;
};
// function Component(value: number) { // We can define the type (static type) or (dynamic type)
function Component(options: ComponentOptions) {
return (constructor: Function) => {
console.log("Component Called");
constructor.prototype.options = options;
console.log(constructor.prototype.options);
constructor.prototype.userId = Date.now();
constructor.prototype.insertInDom = () => {
console.log("Inserted the component In Dom");
};
};
}
// @Component(5) // static type difinition
@Component({ selector: "#my-div" }) // Dynamic way
class ProfileComponent {
// We have every thing from prototype here
}
Method Decorators
we can re-write the class methods using the decorators and also get their values as well.
// Created a decorator that rewrite the bottom class function
function Log(target: any, methodName: string, descriptor: PropertyDescriptor) {
/**
* methodName is the name of function (say of Person)
* descriptor is the function that access to the value
*
*/
const original = descriptor.value as Function;
descriptor.value = function (...args: any) { // here we got the argument here (good morning)
console.log("Before");
original.call(this, ...args); // calling original function from the person class
console.log("After");
};
}
class Person {
@Log
say(message: string) {
console.log("Person Say " + message);
}
}
const person = new Person();
person.say("good morning");
Accessor Decorators
We can define decorators with getters and setters in typescript
function Caplitalize(target: any, methodName: string, descriptor: PropertyDescriptor) {
const original = descriptor.get;
descriptor.get = function () {
const result = original?.call(this);
return typeof result === "string" ? result.toUpperCase() : result;
};
}
class Person {
constructor(public firstname: string, public lastname: string) {}
@Caplitalize
get fullName() {
return `${this.firstname} ${this.lastname}`;
}
}
let person = new Person("Nima", "Prmi");
console.log(person.fullName);
Property Decorators
with property decorators we can define decoration with properties of the classes
function MinLength(length: number) {
return (target: any, propertyName: string) => {
let value: string;
const descriptor: PropertyDescriptor = {
get() {
return value;
},
set(newValue: string) {
if (newValue.length < length) throw new Error(`${propertyName} must be at least ${length}`);
value = newValue;
},
};
Object.defineProperty(target, propertyName, descriptor);
};
}
class User {
@MinLength(4)// passing argument to the funvtion
password: string;
constructor(pasword: string) {
this.password = pasword;
}
}
const user = new User("aaa"); // Will fail because it is 3
const user2 = new User("aaaa"); // Will success because it is 4
Parameter Decorators
We can get meta data from the class parameters in TypeScript. Nothing so use full but you can get position of the parameter and the method name of the parameter
type WatchedParameters = {
methodName: string;
parameterIndex: number;
};
const watchedParameters: WatchedParameters[] = [];
function Watch(target: any, methodName: string, parameterIndex: number) {
watchedParameters.push({
methodName,
parameterIndex,
});
}
class Vehicle {
move(car: string, @Watch speed: number) {}
}
console.log(watchedParameters);