Reputation: 6449
Assuming
abstract class A {};
class B extends A {};
class C extends A {};
I want to accept as a parameter any Subclass of A.
function foo(Subclass: A){
const obj = new Subclass();
}
This wont work. I get the error
This expression is not constructable. Type 'BaseController' has no construct signatures.
Then I tried
function foo(Subclass: typeof A){
const obj = new Subclass();
}
Now I get the error
Cannot create an instance of an abstract class.ts(2511)
Because it is assuming that I am passing A and not a subclass of A.
Is it achievable? How do I get this to work?
Upvotes: 2
Views: 1554
Reputation: 328292
I think you should change the annotation to the following:
function foo(subclass: new () => A) {
const obj = new subclass();
}
Here, we are saying that subclass
is new
able (i.e., it's a constructor function you call with the new
operator), takes no arguments, and constructs a value whose type is assignable to A
. This should accept any concrete subclass of A
as long as it has a no-arg constructor:
foo(B); // okay
foo(C); // okay
It won't accept A
itself, because an abstract class constructor is not considered new
able:
foo(A); // error, A is abstract
Oh, as a note for people making example TypeScript code for Stack Overflow questions: Note that TypeScript's type system is structural. With the example definitions you gave, instances of A
, B
, and C
are considered the same, empty type. And all objects are assignable to the empty type, so this also works:
foo(Date); // okay also
To prevent that, you should add properties to A
, B
, and/or C
to distinguish them structurally, such as:
abstract class A {
a = "A"
};
class B extends A {
b = "B"
};
class C extends A {
c = "C"
};
Which will result in more expected behavior:
foo(B); // okay
foo(C); // okay
foo(A); // error, A is abstract
foo(Date); // error, 'a' is missing
Okay, hope that helps; good luck!
Upvotes: 6
Reputation: 12481
For this to work you need to refer to the class by it's constructor reference.
abstract class A {};
class B extends A {};
class C extends A {};
function foo(Subclass: new () => A) {
const obj = new Subclass();
}
In this case you can pass both B
and C
to foo
since they have constructors. A
will not be accepted since there is no constructor on an abstract class.
Upvotes: 1