Reputation: 1758
I am referring to "this-typing" referenced here, and here.
It is my understanding that using this
as a type refers to the current class, or whatever is left of the dot (thereby allowing inherited methods to refer to their own class instead of their parent's class).
So can someone explain why this doesn't work:
class Test {
children: Array<this>;
constructor() {
this.children = [new Test()];
}
}
(My goal is to do that with an inherited class, but it doesn't work with a base class. Since this
is of type Test
why can't children
be an array of Test
?
Upvotes: 3
Views: 191
Reputation: 164129
No, when using this
as a type you are referring to the instance and not the class.
It's called Polymorphic this types and is meant to be used like this:
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 Builder2D.x()
and Builder2D.y()
would have returned Builder2D
:
x(x: number): Builder2D {
this._x = x;
return this;
}
y(y: number): Builder2D {
this._y = y;
return this;
}
Then this would fail:
let p1 = new Builder3D().x(0).y(0).z(0).build();
With:
Property 'z' does not exist on type 'Builder2D'
In your scenario this isn't the case, you don't want to return this
.
As far as I'm aware there's no type for the class of this
, but you can do:
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
Seems like there's an issue for that: Polymorphic "this" for static members.
Upvotes: 3
Reputation: 37918
Let's define derived class:
class TestDerived extends Test {
someMethod():void { }
}
As you've already pointed out - this
as type refers to current class, so children
member of TestDerived
is of type TestDerived[]
. So we can do something like this:
let b = new TestDerived ();
b.children[0].someMethod();
If typescript will allow us to populate this array (in constructor of super) with instances of Test
, we will loose type safety (someMethod
is not defined in Test
).
Upvotes: 1