¿Puedes crear clases anidadas en TypeScript?

Respuestas:

131

Comenzando con TypeScript 1.6 tenemos expresiones de clase ( referencia ).

Esto significa que puede hacer lo siguiente:

class Foo {
    static Bar = class {

    }
}

// works!
var foo = new Foo();
var bar = new Foo.Bar();
basarat
fuente
1
este ejemplo no funciona en TypeScript 1.6.3: Error TS4028 La propiedad estática pública 'Bar' de la clase exportada tiene o está usando el nombre privado '(Clase anónima)'.
Sergey
1
@Sergey Tuve el mismo problema, así que comencé a usar espacios de nombres según mi respuesta a continuación.
Dan Def
¿Hay alguna forma de crear una interfaz dentro de una clase? es decir, si queremos que la barra sea una interfaz
RoG
@LittaHervi: un caso de uso sería devolver una implementación privada de una interfaz externa de, por ejemplo, un método de fábrica. Otro ejemplo de Java (y otros) son los iteradores que requieren acceso privilegiado a las variables miembro de su clase contenedora y, a través de reglas de alcance, lo hacen automáticamente, pero nunca desea que estos se exporten y se instancian directamente.
Dave
30

Aquí hay un caso de uso más complejo usando expresiones de clase .

Permite que la clase interna acceda a los privatemiembros de la clase externa.

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
fuente
3
@RyanCavanaugh ¿Es un error la capacidad de acceder a miembros privados dentro de una expresión de clase "interna"?
bnieland
5
Verifiqué que este es un uso correcto con el equipo de TypeScript. github.com/Microsoft/TypeScript/issues/…
bnieland
1
¿Es posible acceder al contexto principal sin pasar esto directamente?
shabunc
@shabunc no que yo sepa
bnieland
1
Exactamente lo que estaba buscando, ¡gracias!
Philippe
19

No pude hacer que esto funcione con clases exportadas sin recibir un error de compilación, en su lugar usé espacios de nombres :

namespace MyNamespace {
    export class Foo { }
}

namespace MyNamespace.Foo {
    export class Bar { }
}
Dan Def
fuente
Mismo. 'Foo' solo se refiere a un tipo, pero aquí se usa como espacio de nombres.
Will Beason
12

Si está en el contexto de un archivo de declaración de tipos, puede hacerlo mezclando clases y espacios de nombres:

// 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
fuente