I need to define a type in TypeScript that expresses “any subtype of T
“, where T
is the formal type parameter of a generic type. Moreover, I need to ensure strict subtyping, meaning that instances of type T
are not to be allowed.
The following example shows a use case that uses AnySubtypeOf<T>
i.e., the type I am looking for:
type AnySubtypeOf<T> = ?
Class Parent<T> {
content: T;
children: AnySubtypeOf<T>[];
constructor(parent: Parent<T>) {
this.content = parent.content;
this.children = parent.children;
}
}
The intent behind AnySubtypeOf<T>
is to improve the development experience in the creation of instances of Parent
type. Say we have a class A
and two subclasses B
and C
, both extending from A
. Imagine that we also have a standalone class D
. Here are the expected results for some instantiations:
const a = new A(...);
const b = new B(...);
const c = new C(...);
const d = new D(...);
new Parent<A>({ content: a, children: [ b, c ] }); // ✅
new Parent<A>({ content: a, children: [ b, d ] }); // ❌ since d is not a subclass of A
new Parent<A>({ content: a, children: [ b, a ] }); // ❌ since a is not an strict subclass of A
I understand that TypeScript does not explicitly support existential quantification, making it difficult to come up with a solution to my problem.
As an attempt to reach such a solution, I came up with a definition for AnySubtypeOf<T>
that would try to infer
subtypes:
type InferSubtype<T> = T extends infer S ? S : never
However, this expression does not comply with the intended goal, since it will only return a type S
if it happens to be a supertype of T
(what I want is exactly the opposite). Moreover, infer
is designed to be written after extends
, not before.
Has anyone managed to successfully resolve this issue?