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);

Leave a Reply

Required fields are marked *