Search code examples
typescriptdecorator

'this' becomes undefined in method after apply decorator


Context: I want to build a decorator to run an interceptor to format a return value.

Problem: 'this' becomes undefined after I applied the decorator.

// decorator
function UseAfter(this: any,  fn: (...args: any) => any){
    return (target: any, key: string, descriptor: PropertyDescriptor) => {
        const originalMethod = descriptor.value

        descriptor.value = (...innerArgs:any) => {
            let result = originalMethod.apply(this, innerArgs)

            return fn(result)
        }
    }
}

const middleware = (arg1: any) => {
    return {
        data: JSON.stringify(arg1)
    }
}

class Test {

    otherInstanceMethod() {
        console.log('accessing instance method')    
    }

    @UseAfter(middleware)
    method1() {
        console.log(this) // < --- undefined
        this.otherInstanceMethod()
        return 'ok'
    }
}

const test = new Test()
test.method1()

Solution

  • For sake of completeness.

    We should not use arrow function for descriptor if we want to preserve the context of this.

    // decorator
    function UseAfter(this: any,  fn: (...args: any) => any){
        return (target: any, key: string, descriptor: PropertyDescriptor) => {
            const originalMethod = descriptor.value
    
            // this should not be a arrow function
            descriptor.value = function (...innerArgs:any) { 
                let result = originalMethod.apply(this, innerArgs)
    
                return fn(result)
            }
        }
    }
    
    const middleware = (arg1: any) => {
        return {
            data: JSON.stringify(arg1)
        }
    }
    
    class Test {
        otherInstanceMethod() {
            console.log('accessing instance method')    
        }
    
        @UseAfter(middleware)
        method1() {
            console.log(this)
            this.otherInstanceMethod()
            return 'ok'
        }
    }
    
    const test = new Test()
    test.method1()
    
    
    

    This would output -

    Test {}
    accessing instance method