1

Here is the code where I lose the context when using the spread operator.

Look at function "decorator". Line when I lose context is marked with "ERROR"

/** MethodDecorator example */
class Account {
    public firstName: string;
    public lastName: string;

    public constructor(firstName: string, lastName: string) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @decorator
    public sayMessage(msg: string): string {
        return `${this.firstName} ${this.lastName}: ${msg}`
    }
}

function decorator(target: any, key: string, desc: any): any {
    let originDesc = desc.value;

    desc.value = function(...args: any[]): any {
        return originDesc(...args); // ==> ERROR: context lost
        //return originDesc.apply(this, arguments); // ==> all OK
    };
    return desc;
}

let persone = new Account('John', 'Smith');
let message = persone.sayMessage('Hello world!');
console.log(message); // ==> undefined undefined: Hello world!

As far as I understand originDesc(...args); equals originDesc.apply(this, arguments); so why is my context lost?

roberrrt-s
  • 7,914
  • 2
  • 46
  • 57
Zurab
  • 1,411
  • 3
  • 17
  • 39

2 Answers2

1

That's because you set:

let originDesc = desc.value; // This is where you loose context

and then call originDesc. This is exactly the same case as described here: How to access the correct `this` context inside a callback?.

Also, originDesc(...args) compiles into originDesc.apply(void 0, args). (void because it has not context binded, you can test it on https://www.typescriptlang.org/play/)

Community
  • 1
  • 1
martin
  • 93,354
  • 25
  • 191
  • 226
1

As far as I understand originDesc(...args); equals originDesc.apply(this, arguments); so why context is lost?

No, it doesn't. It's equivalent to originDesc(args[0], args[1], /*etc.*/), which uses the default this (the global object in loose mode, undefined in strict mode).

In that code, you'll need to use .apply:

originDesc.apply(appropriateThisValueHere, args);

or .call:

originDesc.call(appropriateThisValueHere, ...args);

According to this comment in the code:

 //return originDesc.apply(this, arguments); // ==> all OK

appropriateThisValue would be this, so either:

originDesc.apply(this, args);

or

originDesc.call(this, ...args);
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875