Using this
as a type in TypeScript refers to the instance rather than the class.
This concept is known as Polymorphic this types and can be implemented as shown below:
class Point {}
class Point2D extends Point {
constructor(public x: number, public y: number) {
super();
}
}
class Point3D extends Point2D {
constructor(x: number, y: number, public z: number) {
super(x, y);
}
}
class Builder2D {
protected _x: number;
protected _y: number;
x(x: number): this {
this._x = x;
return this;
}
y(y: number): this {
this._y = y;
return this;
}
build(): Point {
return new Point2D(this._x, this._y);
}
}
class Builder3D extends Builder2D {
private _z: number;
z(z: number): this {
this._z = z;
return this;
}
build(): Point3D {
return new Point3D(this._x, this._y, this._z);
}
}
let p1 = new Builder3D().x(0).y(0).z(0).build();
If both Builder2D.x()
and Builder2D.y()
were to return Builder2D
:
x(x: number): Builder2D {
this._x = x;
return this;
}
y(y: number): Builder2D {
this._y = y;
return this;
}
Then there would be a failure with the code snippet provided.
let p1 = new Builder3D().x(0).y(0).z(0).build();
The error displayed would be:
Property 'z' does not exist on type 'Builder2D'
In such a scenario, it's important to not always return this
. Rather, you can consider implementing the following logic to handle instances differently based on their types:
class Test {
public children: Array<Test>;
constructor() {
this.children = [new Test()];
}
}
interface OtherTest {
children: Array<OtherTest>;
}
class OtherTest extends Test {
constructor() {
super();
this.children.push(new Test(), new OtherTest());
}
}
let t1 = new Test();
let c1 = t1.children[0]; // typeof c1 is Test
let t2 = new OtherTest();
let c2 = t2.children[0]; // typeof c2 is OtherTest
This demonstrates a way to manage different child instances within a parent class hierarchy.
Edit
There appears to be an open issue regarding Polymorphic "this" for static members on the TypeScript repository: Polymorphic "this" for static members.