Using typescript decorators to mandate a parameter in methods

1.6k Views Asked by At

In a typescript project, there are about 2000+ events(methods) that are fired when user triggers an operation and when that operation get finished. So, for all the events that are triggered when an operation gets finished, I want to have some kind of performance metrics, so a parameter 'executionTime' should be mandatory. I am planning to add method decorator above all those events for which execution time must be present as a parameter. Below is my code

class AllEvents {

    @performanceDecorator()
    public static firstEvent(param1: string, param2: string, executionTime: number): void {
        //some tasks...
    }

    @performanceDecorator()
    public static secondEvent(param1: string, param2: string): void {
        //some tasks...
    }

    @performanceDecorator()
    public static thirdEvent(param1: string, param2: string, executionTime: number): void {
        //some tasks...
    }
}

function performanceDecorator(value: boolean) {
    //..................
}

I am new to typescript, and not able to figure out the code that I should write in the body of function performanceDecorator, such that if some method does not have a parameter named 'executionTime', it will throw errors.

1

There are 1 best solutions below

0
On BEST ANSWER

Expanding on my earlier comment

Since the number of parameters cannot be fixed in your scenario, there will be no easy way to figure out which one of your parameter is the executionTime.

So make an options class with the expected parameters as the properties to it. Like this

class EventOptions {
    public params: string[];
    public executionTime?: number;
}

class AllEvents {

    @performanceDecorator
    public static firstEvent(eventOptions: EventOptions): void {
        //some tasks...
        console.log(eventOptions.params, eventOptions.executionTime);
    }

    @performanceDecorator
    public static secondEvent(eventOptions: EventOptions): void {
        //some tasks...
    }

    @performanceDecorator
    public static thirdEvent(eventOptions: EventOptions): void {
        //some tasks...
    }
}

Here, I have made the executionTime as an optional parameter to suit your usecase. But you can go ahead and make it a required field and then you wont need to have a decorator to check the validity of the field. Typescript will do it for you.


And then to move on to the decorator:

Function Decorators have three parameters to it,

  • target which is the calling class, in this case AllEvents
  • propertyKey which is the name of the method as a string
  • descriptor which is a property descriptor. It has all the metadata related to your function

And we can write your decorator as:

function performanceDecorator(
    target: Object,
    propertyKey: string,
    descriptor: PropertyDescriptor) {
        const originalMethod = descriptor.value;

        descriptor.value = (...args) => {
            if (!args[0].executionTime) {
                throw Error("Execution Time is missing!");
            }
            return originalMethod.apply(this, args);
        }
        return descriptor;
}

Here, we first take the original method implementation out. And then use a condition to check the availability of executionTime parameter. If not present, we thorw an error. And if present we call the original method implementation.