JS TS apply decorator to all methods / enumerate class methods

前端 未结 1 1989
遥遥无期
遥遥无期 2021-02-08 08:55

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

class User {
    @log
    delete() {}

    @log
    create() {}

    @         


        
相关标签:
1条回答
  • 2021-02-08 09:50

    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]
            };
        }
    }
    
    0 讨论(0)
提交回复
热议问题