Search code examples
node.jstypescriptabstract-class

A function to return a class which extends a derived class of an abstract class


I would like to make a funciton to return a class which extends a derived class of an abstract class in Typescript. I think Abstract Construct Signature should be the one I should use. However, Typescript prompts "Non-abstract class 'SayHelloDerived' does not implement all abstract members of 'Base'." Here is a simplified code.

// @errors: 18052
abstract class Base {
  abstract getName(): string;
  printName() {
    console.log("a")
  }
}
class Derived extends Base {
  getName() {
    return "";
  }
}
function makeSayHelloDerived(DerivedBase: new () => Base) {
  return class SayHelloDerived extends DerivedBase {
    sayHello() {
      console.log("hello!");
    }
  }
}

const Derived2 = makeSayHelloDerived(Derived);
const derived2 = new Derived2;
derived2.sayHello();

const Derived3 = makeSayHelloDerived(Base);
const derived3 = new Derived3;
derived3.sayHello();

Typescript Playground link

The second error is expected, but the first one is not.

I expect Typescript can recognize parameter "DerivedBase" in function "makeSayHelloDerived" as a derived class of abstract "Base" class. It should not prompt any error, but it prompts now. I have googled around and search stackOverflow here about "Abstract Construct Signature," but no luck. Did I have anything wrong?


Solution

  • The easy solution would be to change the type of the parameter to new () => Derived, but I suppose that's not what you want - you want to accept any non-abstract class that inherits from Base.

    I'm not certain how exactly this works, but I managed to do this by explicitly adding the concrete method signature to the type of the construct signature:

    function makeSayHelloDerived(DerivedBase: new () => Base & { getName(): string }) {
      return class SayHelloDerived extends DerivedBase {
        sayHello() {
          console.log("hello!");
        }
      }
    }