Can someone help me understand following things as when I am using method decorator in TS -
base
is not callable in Derived class?val
is undefined
even though it is being initialized through Derived class constructor?I have added inline comments in code to highlight parts I am referring to, any help is much appreciated, thanks in advance!
(TS playground if someone want's to have a look at trans-compiled code, play around and see the error for themselves).
const decorator = (val: string) => {
return function (t: any, pk: any, d: any) {
console.log("decorator val " + val)
const ow = d.value
d.value = (props: any) => {
console.log({t, d})
console.log("decorator ", { props })
return ow.call(t, props)
}
}
}
abstract class Base {
protected val: string
protected abstract abstractFn(val: string): void
protected constructor(val: string) {
this.val = val
}
protected base = (val: string) => {
console.log("base " + val)
}
protected nonArrowFunctionBase(val: string) {
console.log("nonArrowFunctionBase " + val)
}
}
class Derived extends Base {
public constructor(val: string = 'default') {
super(val)
}
@decorator("world")
public abstractFn(val: string) {
// this.val is returning undefined even though it is initialized, why?
console.log('derived:abstractFn ' + val + ' baseval ' + this.val)
// This call is working, why?
this.nonArrowFunctionBase(val)
// This call is not working, why?
this.base(val)
}
}
const test = new Derived()
test.abstractFn('Test')
[LOG]: "decorator val world"
[LOG]: {
"t": {},
"d": {
"writable": true,
"enumerable": false,
"configurable": true
}
}
[LOG]: "decorator ", {
"props": "Test"
}
[LOG]: "derived:abstractFn Test baseval undefined" // Why `this.val` is undefined?
[LOG]: "nonArrowFunctionBase Test" // Why non arrow function is callable?
[ERR]: this.base is not a function // Why `this.base(val)` call fails?
I want to understand when using method decorators, why we're not able access Base class methods/values in Derived class? And how we can make it work with decorators?
You are using an arrow function where you need a proper function:
let a = {
foo(){ console.log('a.foo', {this: this}) /* {this: a} */ }
}
let b = {
foo: function() { console.log('b.foo', {this: this}) /* {this: b} */ }
}
let c = {
foo: () => { console.log('c.foo', {this: this}) /* {this: globalThis} */ }
}
Remember, arrow functions don't have their own this
And the second thing: t
is not this
, it's some other object.
You need an actual this
there:
const decorator = (val: string) => {
return function (t: any, pk: any, d: any) {
console.log("decorator val " + val)
const ow = d.value
d.value = function(props: any) {
// ^^^^^^^^
console.log({t, d})
console.log("decorator ", { props })
return ow.call(this, props)
// ^^^^
}
}
}