If you wish to utilize the polymorphic this type within constructor parameters, you will face limitations.
Regrettably, TypeScript does not support this functionality by default as indicated in microsoft/TypeScript#5449. There have been related discussions and feature requests which highlight this constraint. As of now, there is no straightforward way to specify that the constructor parameter should be dependent on the type of the current class constructor for inheritance in subclasses.
If you require such behavior, TypeScript does not offer it out-of-the-box; instead, you will need to find a workaround.
Polymorphic-this involves "implicit" F-bounded polymorphism, treating this like a generic type parameter constrained to itself. Since implicit functionality is unavailable for constructor parameters, one possible solution is to add a self-bounded type parameter to the class explicitly:
abstract class Parent<T extends Parent<T>> {
public foo: string = "";
constructor(v: Partial<T>) {
Object.assign(this, v);
}
}
This approach works by constraining the type parameter T
to Parent<T>
within Parent<T>
, allowing the use of T
in place of this
. When defining subclasses, explicit declarations are required:
class ChildA extends Parent<ChildA> {
bar: string = "";
}
class ChildB extends Parent<ChildB> {
baz: string = ""
}
Now, your subclasses will function as intended:
new ChildA({ foo: 'foo', bar: 'bar' }).bar;
To simplify referencing Parent
elsewhere in your codebase, you may consider assigning a default value to T
. Several options exist depending on your preference for convenience versus precision. You could opt for any
for maximum convenience, followed by more defined defaults like Parent<any>
and further iterations such as Parent<Parent<any>>
. For extreme accuracy, an option with never
may help identify incorrect uses of Parent
where only concrete subclasses make sense.
It is advisable to evaluate these options against your specific requirements to determine the most suitable choice.
Playground link to code