Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to override and extend method signature in child class in Typescript

I have a base class that I am trying to extend:

export class BaseClass<T extends SomeOtherClass> {
  constructor(param: ParamType) {
  }

  doSomething(param1: Param1Type): BaseClass<T> {
    // do something with param1;
    return this;
  } 
}

My class:

export class MyClass<T extends SomeOtherClass> extends BaseClass<T> {

  constructor(param: ParamType) {
    super(param);
  }

  doSomething(param1: Param1Type, param2: Param2Type): MyClass<T> {
    // super.doSomething(param1);
    // do something with param2;
    return this;
  }
}

but I'm getting a warning:

Property 'doSomething' in type 'MyClass<T>' is not assignable to the same property in base type 'BaseClass<T>'.
  Type '(param1: Param1Type, param2: Param2Type) => MyClass<T>' is not assignable to type '(param1: Param1Type) => BaseClass<T>'.

Is it not possible to extend method signatures in typescript? How do I extend the capabilities of the BaseClass if I need to add a parameter to the overridden method and is this the correct way of calling the parent method in es6 syntax. I'm aware that prior to es6 I could have called BaseClass.prototype.doSomething.call(this, param1).

like image 574
Michael Sutherland Avatar asked Apr 19 '18 19:04

Michael Sutherland


People also ask

How do you overwrite methods in TypeScript?

To override a class method in TypeScript, extend from the parent class and define a method with the same name. Note that the types of the parameters and the return type of the method have to be compatible with the parent's implementation.

How do you override a function in child class?

To override a function you must have the same signature in child class. By signature I mean the data type and sequence of parameters. Here we don't have any parameter in the parent function so we didn't use any parameter in the child function.

How do I override a 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.

Does TypeScript support function overriding?

TypeScript override method can be used to implement overriding in TypeScript Method overriding in TypeScript is a language feature that allows a derived class to provide a specific implementation of a method that is already provided by one of its or base classes.


1 Answers

The problem as pointed out by others is that if param2 is required it breaks polymorphism:

// We should be able to do this assignment 
let baseRef: BaseClass<SomeOtherClass> = new MyClass<SomeOtherClass>(""); 
baseRef.doSomething("") // param2 is not required by the base class so MyClass will not receive it even though it NEEDS it

One solution, is to make the second parameter optional, so the call baseRef.doSomething("") is valid for the derived type as well :

export class MyClass<T extends SomeOtherClass> extends BaseClass<T> {

    constructor(param: string) {
        super(param);
    }

    doSomething(param1: string, param2?: string): MyClass<T> {
        super.doSomething(param1);
        return this;
    }
}

A second solution, if we only want to share code between the classes, is to disallow the assignment let baseRef: BaseClass<SomeOtherClass> = new MyClass<SomeOtherClass>(""); by not really inheriting BaseClass but rather inherit a class that excludes the doSomething method:

type PartialBaseClass = new <T> (param: string)  => { [P in Exclude<keyof BaseClass<T>, 'doSomething'>] : BaseClass<T>[P] }
const PartialBaseClass:PartialBaseClass = BaseClass

export class MyClass<T extends SomeOtherClass> extends PartialBaseClass<T> {

    constructor(param: string) {
        super(param);
    }

    doSomething(param1: string, param2: string): MyClass<T> {
        BaseClass.prototype.doSomething.call(this, param1);
        return this;
    }
}
// This is now invalid ! 
let baseRef: BaseClass<SomeOtherClass> = new MyClass<SomeOtherClass>("")    ;
like image 165
Titian Cernicova-Dragomir Avatar answered Oct 14 '22 02:10

Titian Cernicova-Dragomir