ChadF ChadF - 26 days ago 17
TypeScript Question

Typescript "this-typing" confusion

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
?

Answer

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();

(code in playground)

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

(code in playground)


Edit

Seems like there's an issue for that: Polymorphic "this" for static members.

Comments