0

Basically, I have the following TypeScript code:

export class ClassA {

  method1() {
    this.method2(new ClassB().method3);
  }

  method2(functionReference: () => void) {
    functionReference();
  }

}

export class ClassB {

  method3() {
    this.method4();
  }

  method4() {
    console.log("method4 invoked");
  }

}

Being more familiar with other OO programming languages (Java, C#, C++), I would expect that running new A().method1(); would eventually cause method4 in ClassB to be invoked. Instead I run into the problem, that this is undefined when method3 is eventually run and the execution fails:

TypeError: Cannot read properties of undefined (reading 'method4')

I am aware of all the trickery needed to get this to work in JavaScript, but I had hoped for the behaviour to be more intuitive in TypeScript. As long as method3 is a non-static method, I would expect to be able to reference this in the method, no matter from where the method is invoked.

Is there a not too cumbersome pattern available in TypeScript allowing me to use non-static methods as callback functions like I am trying to do here, or is it only possible to use static methods? The latter does not really sound correct, because if it had been so, I would expect the compiler to fail on this.method2(new ClassB().method3) where I try to pass a non-static method as a function reference.

jarnbjo
  • 33,923
  • 7
  • 70
  • 94
  • Does this answer your question? [How to access the correct \`this\` inside a callback](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – jonrsharpe Oct 12 '21 at 11:13
  • @jonrsharpe No, ignoring that the question is related to JavaScript, if I don't miss anything obvious, the question relates to how I can access `this` (in the context of ClassA.method1) from within the callback function ClassB.method3. I am asking how to use `this` (in the context of ClassB.method3) from within ClassB.method3. – jarnbjo Oct 12 '21 at 11:26
  • You _should_ ignore that that question is related to JavaScript! `this` is resolved at runtime, when TypeScript and its type information no longer exists. And which context you get is just a matter of which you `.bind`. – jonrsharpe Oct 12 '21 at 11:48

2 Answers2

2

In javascript the class methods are not bind to its scope when you call them through a reference.

Your code will work correctly if you bind the function to the instance, or if you wrap the call in a function.

Some examples of how you could rewrite the method1 in class ClassA to make things work.

Binding the context to the function:

  method1() {
    const instance = new ClassB();
    this.method2(instance.method3.bind(instance));
  }

Wrapping the call:

  method1() {
    this.method2(()=>new ClassB().method3());
  }
Givi
  • 79
  • 4
  • 1
    Thanks a lot. I had already played around with similar code, even tried the second approach just as you suggested, but didn't get it to work. The problem was that I had a syntax error somewhere else in my code and if you run a Karma test from WebStorm and the compiler fails, you don't see the compiler error, but the test is rerun with the last 'good' compile result. Changes to the compileable code do not have an effect until you fix the unrelated code problems. Now I've learned even two things at once. – jarnbjo Oct 12 '21 at 11:37
1

You can define the method whose reference you want to pass as a class property

class ClassB {

  method3 = () => {
    this.method4();
  }

  method4() {
    console.log("method4 invoked");
  }

}

this way it will be defined as arrow function upon initialization and the this reference will be preserved

TS Playground

Teneff
  • 30,564
  • 13
  • 72
  • 103
  • 1
    Thanks a lot, although I prefer Givi's solution since I only have to change the code where I use the method and not in the implementation of ClassB (which is not necessarily my code, but could also be from an included library). – jarnbjo Oct 12 '21 at 11:34
  • The only preference I'd have for my code is that you'd be able to create an adapter for the library and you wont't have to care about the implementations across your application – Teneff Oct 12 '21 at 11:36