Candy Cup Analogy
Versão 1: Um copo para cada doce
Digamos que você escreveu um código como este:
Mod1.ts
export namespace A {
export class Twix { ... }
}
Mod2.ts
export namespace A {
export class PeanutButterCup { ... }
}
Mod3.ts
export namespace A {
export class KitKat { ... }
}
Você criou esta configuração:
Cada módulo (folha de papel) recebe o seu próprio copo chamado A
. Isso é inútil - você não está realmente organizando seu doce aqui, apenas adicionando uma etapa adicional (tirando-a do copo) entre você e as guloseimas.
Versão 2: um copo no escopo global
Se você não estava usando módulos, você pode escrever um código como este (observe a falta de export
declarações):
global1.ts
namespace A {
export class Twix { ... }
}
global2.ts
namespace A {
export class PeanutButterCup { ... }
}
global3.ts
namespace A {
export class KitKat { ... }
}
Este código cria um espaço A
para nome mesclado no escopo global:
Essa configuração é útil, mas não se aplica aos módulos (porque os módulos não poluem o escopo global).
Versão 3: Indispensável
Voltando ao exemplo original, os copos A
, A
e A
não está fazendo nenhum favor. Em vez disso, você pode escrever o código como:
Mod1.ts
export class Twix { ... }
Mod2.ts
export class PeanutButterCup { ... }
Mod3.ts
export class KitKat { ... }
para criar uma imagem parecida com esta:
Muito melhor!
Agora, se você ainda está pensando em quanto realmente deseja usar o espaço para nome com seus módulos, continue lendo ...
Estes não são os conceitos que você está procurando
Precisamos voltar às origens do porque os namespaces existem em primeiro lugar e examinar se esses motivos fazem sentido para módulos externos.
Organização : os namespaces são úteis para agrupar objetos e tipos relacionados à lógica. Por exemplo, em C #, você encontrará todos os tipos de coleção System.Collections
. Ao organizar nossos tipos em namespaces hierárquicos, fornecemos uma boa experiência de "descoberta" para usuários desses tipos.
Conflitos de nome : os espaços para nome são importantes para evitar colisões de nomes. Por exemplo, você pode ter My.Application.Customer.AddForm
e My.Application.Order.AddForm
- dois tipos com o mesmo nome, mas um espaço para nome diferente. Em um idioma em que todos os identificadores existem no mesmo escopo raiz e todos os assemblies carregam todos os tipos, é essencial ter tudo em um espaço para nome.
Esses motivos fazem sentido em módulos externos?
Organização : Módulos externos já estão presentes em um sistema de arquivos, necessariamente. Temos que resolvê-los por caminho e nome de arquivo, para que exista um esquema de organização lógica para usar. Podemos ter uma /collections/generic/
pasta com um list
módulo.
Conflitos de nome : isso não se aplica em todos os módulos externos. Dentro de um módulo, não há razão plausível para ter dois objetos com o mesmo nome. Do lado do consumo, o consumidor de qualquer módulo pode escolher o nome que usará para se referir ao módulo, portanto, conflitos de nomes acidentais são impossíveis.
Mesmo que você não acredite que esses motivos sejam tratados adequadamente pela maneira como os módulos funcionam, a "solução" de tentar usar espaços para nome em módulos externos nem funciona.
Caixas em Caixas em Caixas
Uma história:
Seu amigo Bob liga para você. "Eu tenho um ótimo novo esquema de organização em minha casa", diz ele, "venha conferir!". Legal, vamos ver o que Bob inventou.
Você começa na cozinha e abre a despensa. Existem 60 caixas diferentes, cada uma rotulada como "Despensa". Você escolhe uma caixa aleatoriamente e abre-a. Dentro, há uma única caixa chamada "Grãos". Você abre a caixa "Grãos" e encontra uma única caixa chamada "Macarrão". Você abre a caixa "Pasta" e encontra uma única caixa chamada "Penne". Você abre esta caixa e encontra, como esperado, um saco de macarrão penne.
Um pouco confuso, você pega uma caixa adjacente, também chamada de "Despensa". Dentro, há uma única caixa, novamente rotulada como "Grãos". Você abre a caixa "Grãos" e, novamente, encontra uma única caixa chamada "Macarrão". Você abre a caixa "Pasta" e encontra uma única caixa, esta é rotulada "Rigatoni". Você abre esta caixa e encontra ... um saco de macarrão rigatoni.
"É ótimo!" diz Bob. "Tudo está em um espaço para nome!".
"Mas Bob ..." você responde. "O esquema da sua organização é inútil. Você precisa abrir um monte de caixas para chegar a qualquer coisa, e não é realmente mais conveniente encontrar alguma coisa do que se você tivesse colocado tudo em uma caixa em vez de três . De fato, desde o seu a despensa já está classificada de prateleira a prateleira, você não precisa das caixas. Por que não colocar a massa na prateleira e buscá-la quando precisar? "
"Você não entende - preciso garantir que ninguém mais coloque algo que não pertença ao espaço para nome 'Despensa'. E organizei com segurança toda a minha massa no Pantry.Grains.Pasta
espaço para nome, para que eu possa encontrá-lo facilmente"
Bob é um homem muito confuso.
Os módulos são sua própria caixa
Você provavelmente teve algo semelhante acontecendo na vida real: você pede algumas coisas na Amazon e cada item aparece em sua própria caixa, com uma caixa menor dentro, com o item embrulhado em sua própria embalagem. Mesmo se as caixas internas forem semelhantes, as remessas não serão úteis "combinadas".
Seguindo a analogia da caixa, a principal observação é que os módulos externos são sua própria caixa . Pode ser um item muito complexo, com muitas funcionalidades, mas qualquer módulo externo é sua própria caixa.
Orientação para módulos externos
Agora que descobrimos que não precisamos usar 'namespaces', como devemos organizar nossos módulos? Seguem alguns princípios e exemplos orientadores.
Exporte o mais próximo possível do nível superior
- Se você estiver exportando apenas uma única classe ou função, use
export default
:
MyClass.ts
export default class SomeType {
constructor() { ... }
}
MyFunc.ts
function getThing() { return 'thing'; }
export default getThing;
Consumo
import t from './MyClass';
import f from './MyFunc';
var x = new t();
console.log(f());
Isso é ideal para os consumidores. Eles podem nomear seu tipo como quiserem ( t
nesse caso) e não precisam fazer pontuações estranhas para encontrar seus objetos.
- Se você estiver exportando vários objetos, coloque-os todos no nível superior:
MyThings.ts
export class SomeType { ... }
export function someFunc() { ... }
Consumo
import * as m from './MyThings';
var x = new m.SomeType();
var y = m.someFunc();
- Se você estiver exportando um grande número de coisas, só então use a palavra-chave
module
/ namespace
:
MyLargeModule.ts
export namespace Animals {
export class Dog { ... }
export class Cat { ... }
}
export namespace Plants {
export class Tree { ... }
}
Consumo
import { Animals, Plants} from './MyLargeModule';
var x = new Animals.Dog();
Bandeiras vermelhas
Todos os seguintes são sinais de alerta para a estruturação do módulo. Verifique se você não está tentando nomear seus módulos externos, se algum deles se aplicar aos seus arquivos:
- Um arquivo cuja única declaração de nível superior é
export module Foo { ... }
(remova Foo
e mova tudo 'para cima' em um nível)
- Um arquivo que possui um único
export class
ou export function
que não éexport default
- Vários arquivos com o mesmo
export module Foo {
nível superior (não pense que eles serão combinados em um Foo
!)