คุณสามารถสร้างคลาสที่ซ้อนกันใน TypeScript ได้หรือไม่?


93

มีวิธีการซ้อนคลาสใน TypeScript หรือไม่ เช่นฉันต้องการใช้มันเช่น:

var foo = new Foo();
var bar = new Foo.Bar();

2
สำหรับ typescript รุ่นเก่า (<1.6) โปรดดูวิธีการซ้อนคลาสใน typescript หรือไม่
Rahul Tripathi

คำตอบ:


132

เริ่มต้นด้วย TypeScript 1.6 เรามีนิพจน์คลาส ( อ้างอิง )

ซึ่งหมายความว่าคุณสามารถทำสิ่งต่อไปนี้:

class Foo {
    static Bar = class {

    }
}

// works!
var foo = new Foo();
var bar = new Foo.Bar();

1
ตัวอย่างนี้ใช้ไม่ได้ใน typescript 1.6.3: ข้อผิดพลาด TS4028 Public static property 'Bar' ของคลาสที่เอ็กซ์พอร์ตมีหรือกำลังใช้ชื่อส่วนตัว '(คลาสไม่ระบุชื่อ)'
Sergey

1
@Sergey ฉันมีปัญหาเดียวกันจึงเริ่มใช้เนมสเปซตามคำตอบด้านล่าง
Dan Def

มีวิธีสร้างอินเทอร์เฟซภายในคลาสหรือไม่? เช่นถ้าเราต้องการให้ Bar นั้นเป็นส่วนต่อประสาน
RoG

@LittaHervi - กรณีการใช้งานหนึ่งจะส่งคืนการใช้งานอินเทอร์เฟซภายนอกแบบส่วนตัวจากตัวอย่างเช่นวิธีการโรงงาน อีกตัวอย่างหนึ่งจาก Java (และอื่น ๆ ) คือตัวทำซ้ำที่ต้องการการเข้าถึงพิเศษสำหรับตัวแปรสมาชิกของคลาสที่มีและผ่านกฎการกำหนดขอบเขตโดยอัตโนมัติ แต่คุณไม่ต้องการให้ส่งออกและสร้างอินสแตนซ์โดยตรง
Dave

35

นี่คือกรณีการใช้งานที่ซับซ้อนมากขึ้นโดยใช้การแสดงออกในชั้นเรียน

ช่วยให้ชั้นในสามารถเข้าถึงprivateสมาชิกของชั้นนอกได้

class classX { 
    private y: number = 0; 

    public getY(): number { return this.y; }

    public utilities = new class {
        constructor(public superThis: classX) {
        }
        public testSetOuterPrivate(target: number) {
            this.superThis.y = target;
        }
    }(this);    
}

const x1: classX = new classX();
alert(x1.getY());

x1.utilities.testSetOuterPrivate(4);
alert(x1.getY());

codepen


3
@RyanCavanaugh ความสามารถในการเข้าถึงสมาชิกส่วนตัวภายในการแสดงออกของคลาส "ภายใน" เป็นจุดบกพร่องหรือไม่?
bnieland

5
ฉันยืนยันว่านี่เป็นการใช้งานที่ถูกต้องกับทีม TypeScript github.com/Microsoft/TypeScript/issues/…
bnieland

1
เป็นไปได้ไหมที่จะเข้าถึงบริบทหลักโดยไม่ผ่านสิ่งนี้โดยตรง
shabunc

@shabunc ไม่ให้ความรู้ของฉัน
bnieland

19

ฉันไม่สามารถทำให้สิ่งนี้ทำงานกับคลาสที่ส่งออกโดยไม่ได้รับข้อผิดพลาดในการคอมไพล์ฉันใช้เนมสเปซแทน:

namespace MyNamespace {
    export class Foo { }
}

namespace MyNamespace.Foo {
    export class Bar { }
}

เหมือนกัน. 'Foo' หมายถึงประเภทเท่านั้น แต่จะถูกใช้เป็นเนมสเปซที่นี่
Will Beason

12

หากคุณอยู่ในบริบทของไฟล์การประกาศประเภทคุณสามารถทำได้โดยผสมคลาสและเนมสเปซ:

// foo.d.ts
declare class Foo {
  constructor();
  fooMethod(): any;
}

declare namespace Foo {
  class Bar {
    constructor();
    barMethod(): any;
  }
}

// ...elsewhere
const foo = new Foo();
const bar = new Foo.Bar();
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.