Home > Net >  Method overloading with an abstract base class
Method overloading with an abstract base class

Time:03-28

I have a scenario where an abstract base class has an abstract method. A second class extends this base class and adds overloaded methods for this abstract method, without actually implementing the abstract method. And a third class which extends the second class, which actually implements the abstract base class method (playground):

abstract class A {
    public abstract test(o?: object): unknown;
}

abstract class B extends A {
    public test(o?: object): unknown;
    public test(s: string): unknown;
    public test(n: number): unknown;
    public test(sOrN?: string | number | object): unknown {
        if (typeof sOrN === "string") {
            return String(sOrN);
        }

        return Number(sOrN);
    }
}

class C extends B {
    public test(o?: object): unknown {
        return undefined;
    }
}

A similar question was asked here, but that doesn't discuss an abstract base method. The suggestion there is to include the abstract method as overloading signature in class B. However, I cannot implement it there. It will be implemented in class C.

With that approach I get an error in class C:

Property 'test' in type 'C' is not assignable to the same property in base type 'B'. Type '(o?: object | undefined) => unknown' is not assignable to type '{ (o?: object | undefined): unknown; (s: string): unknown; (n: number): unknown; }'. Types of parameters 'o' and 's' are incompatible. Type 'string' is not assignable to type 'object'.(2416)

How can this be solved without having to include the abstract base method signature in the overload?

CodePudding user response:

In TypeScript (and JavaScript) class methods are resolved by name, the parameters and their types are not involved. It works the same way as resolving any other property it's just that the value is a function and not a primitive type.

You can't actually have different implementations of a method that take different parameters. Overloading in TypeScript is simply a way for you to define valid combinations of types your function will accept which is why all but one of the function definitions are empty. There can only ever be one method called test and that same implementation will be called regardless of what arguments you supply.

You can replace the implementation of test in a derived class but again, that becomes the one implementation, the runtime won't pick the derived or the base implementation depending on which arguments you pass. If you call c.test() you will always get the implementation defined in C.

Because B is defining some overloads for test, when you provide the implementation in C you have to also satisfy the overloads of B because the C implementation entirely replaces the one in B and will have to be able to cope with all the parameter variants B.test wants as well and that is what the error message is telling you.

If you change C to this so that its test matches the one in B then the compiler is happy...

class C extends B {
    public test(sOrN?: string | number | object): unknown {
        return undefined;
    }
}
  • Related