TypeScript: Generic `{ new(...args: any[]): T }` parameter doesn't work for abstract classes
Following up on https://github.com/Microsoft/TypeScript/issues/5236#issuecomment-147738916, the proposed solution doesn’t cover all bases now that abstract classes are supported.
abstract class A {}
class B extends A {}
function isType<T>(value: any, key: { new(...args: any[]): T }): boolean {
return value instanceof key;
}
console.log(isType((new B), A))
Error TS2345: Argument of type ‘typeof A’ is not assignable to parameter of type ‘new (…args: any[]) => A’. Cannot assign an abstract constructor type to a non-abstract constructor type.
On a related note, interfaces and abstract classes feel a bit kludgey since I can’t seem to verify that an arbitrary object actually conforms to them. I can require them as parameter types and use user-defined type guards, but there’s no generic equivalent to instanceof.
About this issue
- Original URL
- State: closed
- Created 9 years ago
- Reactions: 14
- Comments: 21 (7 by maintainers)
+1 for this issue, I have a real-life scenario as well where I have a function which accepts constructors but only for reflection purposes; e.g. it does instanceof checks but nothing else with the constructor, just like the above examply:
Currently I have to cast the type to
anywhen passing it toisType. Being able to mark the constructor as (possibly)abstractin the type would solve this issue.My use case is mixin applied to abstract class:
Currently I need to cast
AbstractBasetoConstructor<AbstractBase>. It would be nice to have some possibly abstract constructor type or class type. Here is my example with more details.the error is that
Ais not constructable. your functionisTypesays it expects things that it can construct, though in the implementation it never constructs anything. so you can not pass an abstract class to a function that may use it to construct objects. consider:i think we need a way to enable the scenario, though this needs a propsal
@unional As mentioned in my linked issue above, you can do the following and everything works as expected:
@vojtechhabarta wrote:
Upon receiving
AbstractBasecast toConstructorwithinMixin(), the compiler both fails to inform me of failures to implement abstract properties ofAbstractBaseand fails to require that I declare such a partially-implemented class asabstract.@AdamWillden I didn’t get the explanation in the last edit, but I think I agree with the first notion.
an abstract class is a class for all intents except that you can’t use it directly with
new. so it makes no sense to give it anewcall signature.However you should be able to inherit it and call it as
super(), and right now typescript uses thenewsignature as thesuper()signature.so maybe add an optional explicit super signature, and allow the
newsignature to be used as a fallback?to clarify, here’s some pseudo-types following @sccolbert 's code example:
one can also think of something like this:
but I really don’t know how I feel about that