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()
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