Chris
Chris

Reputation: 14198

js apply decorator programmatically

I have a class decorator and would like to use it to apply another decorator to all methods within the class, but I am not quite sure how to apply a decorator programmatically without the @ syntax:

@LogAllMethods
class User {
    greet() {
        console.log('Hello')
    }
}

function LogAllMethods(target) {
    for (const key in Object.keys(target.prototype)) {
        // apply LogMethod decorator
    }
}

function LogMethod(target, key, descriptor) {
    let method = descriptor.value
    decriptor.value = function(...args) {
        console.log(args)
        method.apply(this, ...args)
    }
}

Upvotes: 5

Views: 1948

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249506

You basically just have to call the decorator function with the target, the key (method name) and the defined descriptor:

function LogAllMethods<T>(target: new (...params: any[]) => T) {
    for (const key of Object.getOwnPropertyNames(target.prototype)) {
        let descriptor = Object.getOwnPropertyDescriptor(target.prototype, key);
        descriptor = LogMethod(target.prototype, key, descriptor);
        if (descriptor) {
            Object.defineProperty(target.prototype, key, descriptor);
        }
    }
}

function LogMethod(target: any, key: symbol | string, descriptor: TypedPropertyDescriptor<any> = undefined) {

    if (descriptor) {
        let method = descriptor.value;
        if (method instanceof Function) {
            descriptor.value = function (...args: any[]) {
                console.log("Log", args)
                method.apply(this, ...args);
            }
        }
        return descriptor;
    } else {
        // descriptor is null for target es5 if the decorator is applied directly to the merhod
        let method = target[key];
        if (method instanceof Function) {
            target[key] = function (...args: any[]) {
                console.log("Log", args)
                method.apply(this, ...args);
            }
        }
    }
}

Upvotes: 3

Related Questions