Override method with different argument types in extended class - Typescript
As mentioned by others this is not a good idea because you break Liskov substitution.
What you can easily do, is provide an override that takes both string
and number
. This allows your class to still be used wherever the base class is expected.
class Base {
public myMethod(myString: string): undefined {
return;
}
}
class Child extends Base {
public myMethod(myNumberOrString: number | string): undefined {
if (typeof myNumberOrString === 'number') {
return super.myMethod(String(myNumberOrString));
} else {
return super.myMethod(myNumberOrString);
}
}
}
There is not a way to do this*. In TypeScript, inheritance implies subtyping, so you can't inherit from a base class while not being a valid subtype of it.
*
Technically not true but I'm not going to mention them because they're gross hacks that you shouldn't do.
It seems there is a way that works, even for return types, at least with TypeScript v 4.02 using an interim class.
But this is breaking Liskov substitution principle since it changes the return type and is not handling the case where the parameter is a string.
So it worths being mentioned just for the sake of knowledge, but in a code review I would not accept this hack, since a subclass should be able to replace the base class without breaking the functionality.
class Base {
public myMethod(myString: string): string {
return myString + myString;
}
}
// weaken
// inspired by comment here: https://github.com/microsoft/TypeScript/issues/3402#issuecomment-385975990
class Interim extends Base {
public myMethod(x: any): any { return super.myMethod(x); }
}
class Child extends Interim {
public myMethod(myNumber: number): number {
return myNumber * myNumber;
}
}
// we can have a helper/utility for this
function weaken(klass: { new(...args: any[]): any; }, key: string) {
return class extends klass {
[key](...args: any[]) { super[key](...args); }
}
}
class ChildOther extends weaken(Base, 'myMethod') {
public myMethod(myNumber: number): number {
return myNumber * myNumber;
}
}
console.log((new Child()) instanceof Base); // true
console.log((new ChildOther()) instanceof Base); // true
console.log(new Base().myMethod('str')); // strstr
console.log(new Child().myMethod(3)); // 9
console.log(new ChildOther().myMethod(3)); // 9