Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript overridden class method and this

Tags:

typescript

I have these two Typescript classes:

class Base {
  value: string;

  lambdaExample = () => {
    this.value = 'one';
  }

  methodExample() {
    this.value = 'two';
  }
}

class Child extends Base {
  lambdaExample = () => {
    super.lambdaExample(); // Error, because I've overwritten (instead of overridden) the method
    this.value = 'three'; // ok
  }

  methodExample() => {
    super.methodExample(); // ok
    this.value = 'four'; // Error: this refers to window, not to the actual this
  }
}

How do I write my methods in such a way that this references are reliable, and I can override methods and call them from the parent class?

like image 785
Jorn Avatar asked Apr 28 '16 14:04

Jorn


People also ask

Can you override method in TypeScript?

When a method is marked with override , TypeScript will always make sure that a method with the same name exists in a the base class. This member cannot have an 'override' modifier because it is not declared in the base class 'SomeComponent'.

How do you override a class method?

When overriding a method, you might want to use the @Override annotation that instructs the compiler that you intend to override a method in the superclass. If, for some reason, the compiler detects that the method does not exist in one of the superclasses, then it will generate an error.

Can you override inherited methods?

To override an inherited method, the method in the child class must have the same name, parameter list, and return type (or a subclass of the return type) as the parent method. Any method that is called must be defined within its own class or its superclass.

Can we override private method in TypeScript?

Using protected is the correct way to solve this! But if you have no access to the parent class (e.g. because it is within a library) you also could overwrite private class member-function in the constructor.


2 Answers

There's actually a good look at the different ways of tackling this problem on Microsoft's Git Wiki. It essentially comes down to this:

  • Bind or wrap the method every time it's called from a different context if you care about inheritance.
  • Turn the method into a property that contains a function if you don't.

There are many more stipulations in the actual Wiki and I really recommend you read the whole thing.

EDIT

An example of wrapping:

Given the class

class SomeClass {
    public someProp: string = "Hello World";

    public someMethod() {
        console.log(this.someProp);
    }

}

If you were to call someMethod from (for example) a click handler - someEl.onclick = instanceOfMyClass.someMethod; - an exception would be raised (assuming window doesn't have a property someProp).

You can circumvent this by either binding the function to instanceOfMyClass (not type-safe, not ES6 compatible) or by manually wrapping it (effectively what bind is doing, anyway):

someEl.onclick = function() {
    someInstanceOfMyClass.someMethod();
};

It's a little bit verbose and pedantic, but by calling someMethod as a property of someInstanceOfMyClass and not passing it into an event handler (which turns it into a property of window) you ensure that this is always an instance of MyClass.

like image 167
Sandy Gifford Avatar answered Nov 15 '22 04:11

Sandy Gifford


Your assumptions about the reasons for the errors are wrong, which I think is the cause of your problem...at least as I understand it.

lambdaExample = () => {
  this.value = 'one';
}

This line, for example is defining a property, not a method on Base, and you can't override a property. The only instance method you've defined in Base is methodExample.

In Child, you're assigning a new variable to lambaExample. Your call to super.lambaExample() fails because that can only access methods via super(); accessing properties is done via this. methodExample in your Child class shows up as a syntax error for me.

Note that you can still call super from Child in the overwritten lambaExample property, but only on methods. This works:

lambdaExample = () => {
  super.methodExample(); // Success on super.<somemethod>()
  this.value = 'three';
}

I'm only aware of one way to declare an instance method in a class, and if you're consistent with that syntax, this works as you would expect:

class Base {
  value: string;

  lambdaExample() {
    this.value = 'one';
  }

  methodExample() {
    this.value = 'two';
  }
}

class Child extends Base {
  lambdaExample() {
    super.lambdaExample();
    this.value = 'three';
  }

  methodExample() {
    super.methodExample();
    this.value = 'four';
  }
}
like image 45
Christopher Currens Avatar answered Nov 15 '22 03:11

Christopher Currens