Können Sie in TypeScript verschachtelte Klassen erstellen?

Lesezeit: 1 Minute

Benutzer-Avatar
Basarat

Gibt es eine Möglichkeit, Klassen in TypeScript zu verschachteln? ZB möchte ich sie verwenden wie:

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

  • Für älteres Typoskript (<1.6) siehe Irgendeine Möglichkeit, Klassen in Typoskript zu verschachteln?

    – Rahul Tripathi

    10. September 2015 um 6:03 Uhr


Benutzer-Avatar
Basarat

In modernem TypeScript gibt es Klassenausdrücke, mit denen Sie eine verschachtelte Klasse erstellen können. Sie können beispielsweise Folgendes tun:

class Foo {
    static Bar = class {
        
    }
}

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

  • Dieses Beispiel funktioniert nicht in Typescript 1.6.3: Fehler TS4028 Die öffentliche statische Eigenschaft „Bar“ der exportierten Klasse hat oder verwendet den privaten Namen „(anonyme Klasse)“.

    – Sergej

    23. Oktober 2015 um 12:23 Uhr

  • @Sergey Ich hatte das gleiche Problem, also fing ich an, Namespaces gemäß meiner Antwort unten zu verwenden.

    – DanDef

    29. September 2016 um 10:57 Uhr

  • Gibt es eine Möglichkeit, eine Schnittstelle innerhalb einer Klasse zu erstellen? dh wenn wir wollen, dass Bar eine Schnittstelle sein wird

    – RoG

    10. Oktober 2018 um 12:03 Uhr


  • @LittaHervi – Ein Anwendungsfall wäre die Rückgabe einer privaten Implementierung einer externen Schnittstelle, beispielsweise von einer Factory-Methode. Ein weiteres Beispiel aus Java (und anderen) sind Iteratoren, die privilegierten Zugriff auf Mitgliedsvariablen ihrer enthaltenden Klasse benötigen und dies durch Scoping-Regeln automatisch tun, aber Sie möchten nie, dass diese direkt exportiert und instanziiert werden.

    – David

    26. November 2019 um 5:57 Uhr

  • Gibt es eine Möglichkeit, die verschachtelte Klasse der übergeordneten Klasse wiederzuverwenden? Klasse Foo {statischer Balken = Klasse {}; FeldA: Balken; //funktioniert nicht: Name ‘Bar’ kann nicht gefunden werden fieldB: Foo.Bar; //funktioniert nicht: ‘Foo’ bezieht sich nur auf einen Typ, wird hier aber als Namensraum verwendet. } // funktioniert! var foo = neues Foo(); var bar = new Foo.Bar();

    – LucasM

    16. November 2021 um 16:01 Uhr


Benutzer-Avatar
bnieland

Hier ist ein komplexerer Anwendungsfall mit Klasse Ausdrücke.

Es erlaubt die innere Klasse um auf die zuzugreifen private Mitglieder von äußere Klasse.

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

Codestift

  • @RyanCavanaugh Ist die Möglichkeit, auf private Mitglieder innerhalb eines “inneren” Klassenausdrucks zuzugreifen, ein Fehler?

    – bnieland

    25. Juli 2017 um 14:51 Uhr

  • Ich habe mit dem TypeScript-Team überprüft, ob dies die richtige Verwendung ist. github.com/Microsoft/TypeScript/issues/…

    – bnieland

    1. August 2017 um 0:34 Uhr

  • Ist es möglich, auf den übergeordneten Kontext zuzugreifen, ohne dies direkt zu übergeben?

    – schabunc

    11. Februar 2020 um 13:31 Uhr

  • @shabunc meines Wissens nicht

    – bnieland

    24. Juli 2020 um 3:02 Uhr

  • Idee Wenn Sie eine “echte” (nicht “statische”) innere Klasse (als Objektvorlage) benötigen, verwenden Sie sie wie () => new class

    – PEZO

    21. Mai 2021 um 12:13 Uhr


Benutzer-Avatar
Dan Def

Ich konnte dies nicht mit exportierten Klassen zum Laufen bringen, ohne einen Kompilierungsfehler zu erhalten, stattdessen habe ich verwendet Namensräume:

namespace MyNamespace {
    export class Foo { }
}

namespace MyNamespace.Foo {
    export class Bar { }
}

  • Dasselbe. ‘Foo’ bezieht sich nur auf einen Typ, wird hier aber als Namensraum verwendet.

    – Will Beason

    10. September 2019 um 19:51 Uhr

Wenn Sie sich im Kontext einer Typdeklarationsdatei befinden, können Sie dies tun, indem Sie Klassen und Namespaces mischen:

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

Benutzer-Avatar
Warnio

Bei dieser Antwort geht es um a nahtlos verschachtelte Klassenimplementierung in TypeScript, das auf der Antwort von @basarat aufbaut.

Um den Typ des zu machen statisch verschachtelte Klasse Bar zugänglich (wie @PeterMoore betonte), deklarieren Sie den Typ der verschachtelten Klasse in einem Namespace. Auf diese Weise können wir die Verknüpfung verwenden Foo.Bar. Durch Verschieben von Typ typeof Foo.Bar.prototype in einen Typ in einem deklarierten Namensraum, müssen wir den Ausdruck nicht wiederholen.

class Foo {
    static Bar = class {
        
    }
}

declare namespace Foo {
    type Bar = typeof Foo.Bar.prototype
}

// Now we are able to use `Foo.Bar` as a type
let bar: Foo.Bar = new Foo.Bar()

Für statische Klassen könnte die folgende Implementierung eleganter sein. Dies funktioniert jedoch nicht mit nicht statischen Klassen.

class Foo { }

namespace Foo {
    export class Bar { }
}

let bar: Foo.Bar = new Foo.Bar()

Um die Klasse zu exportieren, kann eine export-Anweisung hinzugefügt werden, nachdem die Klasse und der Namensraum deklariert wurden, z export default Foo oder export { Foo }.

Um dasselbe mit einer nicht statischen verschachtelten Klasse zu erreichen, sehen Sie sich das folgende Beispiel an.

class Foo {
    Bar = class {
        
    }
}

declare namespace Foo.prototype {
    type Bar = typeof Foo.prototype.Bar.prototype
}

let foo: Foo = new Foo()
let bar: Foo.prototype.Bar = new foo.Bar()

Ich hoffe, das kann hilfreich sein

Fähig:

  • Erstellen Sie eine neue innere Klasseninstanz
  • Greifen Sie auf Instanz-/Prototypmitglieder der äußeren Klasse zu
  • Schnittstellen implementieren
  • Verwenden Sie Dekorateure

Anwendungsfall

export interface Constructor<T> {
    new(...args: any[]): T;
}

export interface Testable {
    test(): void;
}

export function LogClassName<T>() {
    return function (target: Constructor<T>) {
        console.log(target.name);
    }
}

class OuterClass {
    private _prop1: string;

    constructor(prop1: string) {
        this._prop1 = prop1;
    }

    private method1(): string {
        return 'private outer method 1';
    }

    public InnerClass = (
        () => {
            const $outer = this;

            @LogClassName()
            class InnerClass implements Testable {
                private readonly _$outer: typeof $outer;

                constructor(public innerProp1: string) {
                    this._$outer = $outer;
                }

                public test(): void {
                    console.log('test()');
                }

                public outerPrivateProp1(): string {
                    return this._$outer._prop1;
                }
                
                public outerPrivateMethod1(): string {
                    return this._$outer.method1();
                }
            }
            return InnerClass;
        }
    )();
}

const outer = new OuterClass('outer prop 1')
const inner = new outer.InnerClass('inner prop 1');

console.log(inner instanceof outer.InnerClass); // true 
console.log(inner.innerProp1); // inner prop 1
console.log(inner.outerPrivateProp1()); // outer prop 1
console.log(inner.outerPrivateMethod1()); // private outer method 1

1251590cookie-checkKönnen Sie in TypeScript verschachtelte Klassen erstellen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy