Pouvez-vous créer des classes imbriquées dans TypeScript?

89

Existe-t-il un moyen d'imbriquer des classes dans TypeScript. Par exemple, j'aimerais les utiliser comme:

var foo = new Foo();
var bar = new Foo.Bar();
basarat
la source
2
Pour les anciens scripts dactylographiés (<1.6), consultez Any way to nest classes in typescript?
Rahul Tripathi

Réponses:

131

À partir de TypeScript 1.6, nous avons des expressions de classe ( référence ).

Cela signifie que vous pouvez effectuer les opérations suivantes:

class Foo {
    static Bar = class {

    }
}

// works!
var foo = new Foo();
var bar = new Foo.Bar();
basarat
la source
1
cet exemple ne fonctionne pas dans Typescript 1.6.3: Erreur TS4028 Propriété statique publique 'Bar' de la classe exportée a ou utilise le nom privé '(classe anonyme)'.
Sergey
1
@Sergey J'ai eu le même problème, alors j'ai commencé à utiliser les espaces de noms selon ma réponse ci-dessous.
Dan Def le
Existe-t-il un moyen de créer une interface à l'intérieur d'une classe? c'est-à-dire si nous voulons que Bar soit une interface
RoG
@LittaHervi - Un cas d'utilisation serait de retourner une implémentation privée d'une interface externe à partir, par exemple, d'une méthode de fabrique. Un autre exemple de Java (et d'autres) sont les itérateurs qui nécessitent un accès privilégié aux variables membres de leur classe contenante et via des règles de portée le font automatiquement, mais vous ne voulez jamais que ces derniers soient exportés et instanciés directement.
Dave
30

Voici un cas d'utilisation plus complexe utilisant des expressions de classe .

Il permet à la classe interne d'accéder aux privatemembres de la classe externe.

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

bnieland
la source
3
@RyanCavanaugh La possibilité d'accéder à des membres privés dans une expression de classe "interne" est-elle un bogue?
bnieland
5
J'ai vérifié qu'il s'agissait d'une utilisation correcte avec l'équipe TypeScript. github.com/Microsoft/TypeScript/issues/…
bnieland
1
est-il possible d'accéder au contexte parent sans le passer directement?
shabunc
@shabunc pas à ma connaissance
bnieland
1
Exactement ce que je cherchais, merci!
Philippe le
19

Je ne pouvais pas faire fonctionner cela avec les classes exportées sans recevoir une erreur de compilation, à la place j'ai utilisé des espaces de noms :

namespace MyNamespace {
    export class Foo { }
}

namespace MyNamespace.Foo {
    export class Bar { }
}
Dan Def
la source
Même. «Foo» ne fait référence qu'à un type, mais est utilisé ici comme espace de noms.
Will Beason
12

Si vous êtes dans le contexte d'un fichier de déclaration de type, vous pouvez le faire en mélangeant des classes et des espaces de noms:

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