Tìm kiếm trang web

Sự nhầm lẫn về 'this-typing' trong Typescript


Tôi đang nói đến "this-typing" được tham chiếu ở đây, và ở đây.

Theo hiểu biết của tôi, việc sử dụng this như một kiểu dữ liệu đề cập đến lớp hiện tại, hoặc bất cứ thứ gì còn lại sau dấu chấm (từ đó cho phép các phương thức kế thừa tham chiếu đến lớp của chính chúng thay vì lớp cha của chúng).

Vậy có ai có thể giải thích tại sao điều này không hoạt động:

class Test {
    children: Array<this>;

    constructor() {
        this.children = [new Test()];
    }
}

(Mục tiêu của tôi là làm điều đó với một lớp kế thừa, nhưng nó không hoạt động với lớp cơ sở. Vì this có kiểu Test tại sao children lại không thể là một mảng của Test?)

Câu trả lời #1

Không, khi sử dụng this như một kiểu, bạn đang tham chiếu đến thể hiện chứ không phải lớp.
Nó được gọi là kiểu this đa hình và được sử dụng như sau:

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

(mã trong sân chơi)

Nếu Builder2D.x() và Builder2D.y() trả về Builder2D:

x(x: number): Builder2D {
    this._x = x;
    return this;
}

y(y: number): Builder2D {
    this._y = y;
    return this;
}

Sau đó điều này sẽ thất bại:

let p1 = new Builder3D().x(0).y(0).z(0).build();

Với :

Thuộc tính 'z' không tồn tại trên loại 'Builder2D'

Trong tình huống của bạn thì không phải như vậy, bạn không muốn trả về this.
Theo những gì tôi biết thì không có kiểu cho lớp của this, nhưng bạn có thể làm như sau:

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

(mã trong sân chơi)

Chỉnh sửa

Có vẻ như có một vấn đề về điều đó: 'this' đa hình cho các thành viên tĩnh.

Câu trả lời #2

Hãy định nghĩa lớp dẫn xuất:

class TestDerived extends Test {
    someMethod():void { }
}

Như bạn đã chỉ ra - this kiểu tham chiếu đến lớp hiện tại, vì vậy thành viên children của TestDerived là kiểu TestDerived[]. Vì vậy chúng ta có thể làm điều gì đó như sau:

let b = new TestDerived ();
b.children[0].someMethod();

Nếu TypeScript cho phép chúng ta điền đầy mảng này (trong constructor của super) với các thể hiện của Test, chúng ta sẽ mất an toàn kiểu (vì someMethod không được định nghĩa trong Test).

Bài viết liên quan