Typescript decorators not working with arrow functions

后端 未结 1 1836
野的像风
野的像风 2021-01-13 18:12

I have a typescript decorator factory which console logs total time taken to execute a function, actual function execution results and parameters passed to the decorator as

相关标签:
1条回答
  • 2021-01-13 18:20

    performaceLog is supposed to work with prototype methods only because it relies on descriptor, which should be optional.

    There is no descriptor in case of handleMessage = message => ... class field because it doesn't exist on class prototype. Class fields are just assigned to this in constructor.

    This line won't work for same reason:

    descriptor = Object.getOwnPropertyDescriptor(target, key);
    

    In order to patch arrow method in decorator, a trap should be set on class prototype. Here is an example of universal decorator that can be used with both prototype and instance methods; it uses get/set to catch proper this context and cache decorated function to patchFn variable. It returns a descriptor regardless of descriptor parameter:

    function universalMethodDecorator(target: any, prop: string, descriptor?: TypedPropertyDescriptor<any>): any {
        let fn;
        let patchedFn;
    
        if (descriptor) {
            fn = descriptor.value;
        }
    
        return {
            configurable: true,
            enumerable: false,
            get() {
                if (!patchedFn) {
                    patchedFn = (...args) => fn.call(this, ...args);
                }
                return patchedFn; 
            },
            set(newFn) {
                patchedFn = undefined;
                fn = newFn;
            }
        };
    
    }
    

    This applies only to TypeScript decorators. Babel legacy decorators may behave differently.

    As explained in this answer, prototype methods can be preferred to instance methods for several reasons. One of the reasons is that they can be seamlessly decorated because decorators are applied to class prototype. The only real benefit of arrow method is that it is naturally bound to class instance, but since the decorator is already in use, prototype method can be bound in decorator if needed (this is what universalMethodDecorator basically does; it is noop for arrow methods).

    0 讨论(0)
提交回复
热议问题