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