Você pode criar classes aninhadas no TypeScript?

Respostas:

132

A partir do TypeScript 1.6, temos expressões de classe ( referência ).

Isso significa que você pode fazer o seguinte:

class Foo {
    static Bar = class {

    }
}

// works!
var foo = new Foo();
var bar = new Foo.Bar();
Basarat
fonte
1
este exemplo não funciona no texto de tipo 1.6.3: Erro TS4028 A propriedade estática pública 'Bar' da classe exportada tem ou está usando o nome privado '(classe anônima)'.
Sergey
1
@Sergey Eu tive o mesmo problema, então comecei a usar namespaces de acordo com minha resposta abaixo.
Dan Def
Existe uma maneira de criar interface dentro de uma classe? ou seja, se quisermos que a barra seja uma interface
RoG
@LittaHervi - Um caso de uso seria retornar uma implementação privada de uma interface externa de, por exemplo, um método de fábrica. Outro exemplo de Java (e outros) são os iteradores que requerem acesso privilegiado a variáveis ​​de membro de sua classe contida e, por meio de regras de escopo, fazem isso automaticamente, mas você nunca deseja que eles sejam exportados e instanciados diretamente.
Dave
35

Aqui está um caso de uso mais complexo usando expressões de classe .

Ele permite que a classe interna acesse os privatemembros da classe 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
fonte
3
@RyanCavanaugh A capacidade de acessar membros privados dentro de uma expressão de classe "interna" é um bug?
bnieland
5
Eu verifiquei que este é o uso correto com a equipe TypeScript. github.com/Microsoft/TypeScript/issues/…
bnieland
1
é possível acessar o contexto pai sem passar isso diretamente?
shabunc de
@shabunc, não que eu saiba
bnieland
19

Não consegui fazer isso funcionar com classes exportadas sem receber um erro de compilação; em vez disso, usei namespaces :

namespace MyNamespace {
    export class Foo { }
}

namespace MyNamespace.Foo {
    export class Bar { }
}
Dan Def
fonte
Mesmo. 'Foo' refere-se apenas a um tipo, mas está sendo usado como um namespace aqui.
Will Beason de
12

Se você estiver no contexto de um arquivo de declaração de tipo, poderá fazer isso misturando classes e namespaces:

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