JS TS apply decorator to all methods / enumerate class methods

让人想犯罪 __ 提交于 2020-06-25 09:11:06

问题


I would like to apply a decorator function to all methods within a class so I can replace:

class User {
    @log
    delete() {}

    @log
    create() {}

    @log
    update() {}
}

with

@log
class User {
    delete() {}
    create() {}
    update() {}
}

回答1:


Create a class decorator and enumerate the properties on the target's prototype.

For each property:

  1. Get the property descriptor.
  2. Ensure it's for a method.
  3. Wrap the descriptor value in a new function that logs the information about the method call.
  4. Redefine the modified property descriptor back to the property.

It's important to modify the property descriptor because you want to ensure your decorator will work well with other decorators that modify the property descriptor.

function log(target: Function) {
    for (const propertyName of Object.keys(target.prototype)) {
        const descriptor = Object.getOwnPropertyDescriptor(target.prototype, propertyName);
        const isMethod = descriptor.value instanceof Function;
        if (!isMethod)
            continue;

        const originalMethod = descriptor.value;
        descriptor.value = function (...args: any[]) {
            console.log("The method args are: " + JSON.stringify(args));
            const result = originalMethod.apply(this, args);
            console.log("The return value is: " + result);
            return result;
        };

        Object.defineProperty(target.prototype, propertyName, descriptor);        
    }
}

Base Class Methods

If you want this to affect the base class methods as well, then you might want something along these lines:

function log(target: Function) {
    for (const propertyName in target.prototype) {
        const propertyValue = target.prototype[propertyName];
        const isMethod = propertyValue instanceof Function;
        if (!isMethod)
            continue;

        const descriptor = getMethodDescriptor(propertyName);
        const originalMethod = descriptor.value;
        descriptor.value = function (...args: any[]) {
            console.log("The method args are: " + JSON.stringify(args));
            const result = originalMethod.apply(this, args);
            console.log("The return value is: " + result);
            return result;
        };

        Object.defineProperty(target.prototype, propertyName, descriptor);        
    }

    function getMethodDescriptor(propertyName: string): TypedPropertyDescriptor<any> {
        if (target.prototype.hasOwnProperty(propertyName))
            return Object.getOwnPropertyDescriptor(target.prototype, propertyName);

        // create a new property descriptor for the base class' method 
        return {
            configurable: true,
            enumerable: true,
            writable: true,
            value: target.prototype[propertyName]
        };
    }
}


来源:https://stackoverflow.com/questions/47621364/js-ts-apply-decorator-to-all-methods-enumerate-class-methods

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!