Analogía de la Copa Candy
Versión 1: una taza para cada dulce
Digamos que escribiste un 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 { ... }
}
Has creado esta configuración:
Cada módulo (hoja de papel) recibe su propio vaso con nombre A
. Esto es inútil: en realidad no está organizando sus dulces aquí, solo está agregando un paso adicional (sacándolo de la taza) entre usted y las golosinas.
Versión 2: una taza en el alcance global
Si no estaba utilizando módulos, podría escribir código como este (tenga en cuenta la falta de export
declaraciones):
global1.ts
namespace A {
export class Twix { ... }
}
global2.ts
namespace A {
export class PeanutButterCup { ... }
}
global3.ts
namespace A {
export class KitKat { ... }
}
Este código crea un espacio A
de nombres combinado en el ámbito global:
Esta configuración es útil, pero no se aplica en el caso de módulos (porque los módulos no contaminan el alcance global).
Versión 3: ir sin taza
Volviendo al ejemplo inicial, las copas A
, A
y A
no le están haciendo ningún favor. En cambio, podría escribir el código como:
Mod1.ts
export class Twix { ... }
Mod2.ts
export class PeanutButterCup { ... }
Mod3.ts
export class KitKat { ... }
para crear una imagen que se vea así:
¡Mucho mejor!
Ahora, si todavía está pensando en cuánto realmente quiere usar el espacio de nombres con sus módulos, siga leyendo ...
Estos no son los conceptos que estás buscando
Necesitamos volver a los orígenes de por qué existen espacios de nombres en primer lugar y examinar si esas razones tienen sentido para los módulos externos.
Organización : los espacios de nombres son útiles para agrupar objetos y tipos relacionados lógicamente. Por ejemplo, en C #, encontrará todos los tipos de colección System.Collections
. Al organizar nuestros tipos en espacios de nombres jerárquicos, ofrecemos una buena experiencia de "descubrimiento" para los usuarios de esos tipos.
Conflictos de nombres: los espacios de nombres son importantes para evitar las colisiones de nombres. Por ejemplo, puede tener My.Application.Customer.AddForm
y My.Application.Order.AddForm
- dos tipos con el mismo nombre, pero un espacio de nombres diferente. En un lenguaje donde todos los identificadores existen en el mismo ámbito raíz y todos los ensamblajes cargan todos los tipos, es fundamental que todo esté en un espacio de nombres.
¿Tienen sentido esos motivos en los módulos externos?
Organización : los módulos externos ya están presentes en un sistema de archivos, necesariamente. Tenemos que resolverlos por ruta y nombre de archivo, por lo que hay un esquema lógico de organización que podemos usar. Podemos tener una /collections/generic/
carpeta con un list
módulo.
Conflictos de nombre : esto no se aplica en absoluto en los módulos externos. Dentro de un módulo, no hay una razón plausible para tener dos objetos con el mismo nombre. Desde el punto de vista del consumo, el consumidor de cualquier módulo determinado puede elegir el nombre que usará para referirse al módulo, por lo que los conflictos de nombres accidentales son imposibles.
Incluso si no cree que esas razones se aborden adecuadamente por cómo funcionan los módulos, la "solución" de tratar de usar espacios de nombres en módulos externos ni siquiera funciona.
Cajas en Cajas en Cajas
Una historia:
Tu amigo Bob te llama. "Tengo un gran nuevo esquema de organización en mi casa", dice, "¡ven a verlo!". Bien, vamos a ver qué ha ocurrido Bob.
Empiezas en la cocina y abres la despensa. Hay 60 cajas diferentes, cada una etiquetada "Despensa". Elige una caja al azar y la abre. Dentro hay una sola caja etiquetada "Granos". Abre el cuadro "Granos" y encuentra un cuadro individual con la etiqueta "Pasta". Abre el cuadro "Pasta" y encuentra un cuadro individual con la etiqueta "Penne". Abre esta caja y encuentra, como espera, una bolsa de pasta penne.
Ligeramente confundido, recoges una caja adyacente, también etiquetada como "Despensa". Dentro hay una sola caja, nuevamente etiquetada como "Granos". Abre el cuadro "Granos" y, de nuevo, encuentra un cuadro individual etiquetado como "Pasta". Abre la caja de "Pasta" y encuentra una sola caja, esta etiquetada como "Rigatoni". Abres esta caja y encuentras ... una bolsa de pasta rigatoni.
"¡Es genial!" dice Bob "¡Todo está en un espacio de nombres!".
"Pero Bob ..." respondes. "El esquema de su organización es inútil. Debe abrir un montón de cajas para llegar a cualquier cosa, y en realidad no es más conveniente encontrar nada que si hubiera puesto todo en una caja en lugar de tres . De hecho, desde su la despensa ya está ordenada de un estante a otro, no necesita las cajas en absoluto. ¿Por qué no simplemente coloca la pasta en el estante y la recoge cuando la necesita? "
"No entiendes, tengo que asegurarme de que nadie más ponga algo que no pertenezca en el espacio de nombres 'Despensa'. Y he organizado de manera segura toda mi pasta en el Pantry.Grains.Pasta
espacio de nombres para poder encontrarla fácilmente"
Bob es un hombre muy confundido.
Los módulos son su propia caja
Probablemente ha sucedido algo similar en la vida real: usted ordena algunas cosas en Amazon, y cada artículo aparece en su propia caja, con una caja más pequeña dentro, con su artículo envuelto en su propio embalaje. Incluso si las cajas interiores son similares, los envíos no se "combinan" de manera útil.
Siguiendo la analogía de la caja, la observación clave es que los módulos externos son su propia caja . Puede ser un elemento muy complejo con mucha funcionalidad, pero cualquier módulo externo dado es su propia caja.
Orientación para módulos externos
Ahora que hemos descubierto que no necesitamos usar 'espacios de nombres', ¿cómo debemos organizar nuestros módulos? A continuación se presentan algunos principios rectores y ejemplos.
Exporte lo más cerca posible al nivel superior
- Si solo está exportando una sola clase o función, 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());
Esto es óptimo para los consumidores. Pueden nombrar su tipo como quieran ( t
en este caso) y no tienen que hacer puntos extraños para encontrar sus objetos.
- Si está exportando varios objetos, colóquelos todos en el nivel superior:
MyThings.ts
export class SomeType { ... }
export function someFunc() { ... }
Consumo
import * as m from './MyThings';
var x = new m.SomeType();
var y = m.someFunc();
- Si está exportando una gran cantidad de cosas, solo entonces debe usar la palabra clave
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();
Banderas rojas
Todas las siguientes son banderas rojas para la estructuración de módulos. Vuelva a verificar que no está intentando asignar espacios a sus módulos externos si alguno de estos se aplica a sus archivos:
- Un archivo cuya única declaración de nivel superior es
export module Foo { ... }
(eliminar Foo
y mover todo 'arriba' un nivel)
- Un archivo que tiene un solo
export class
o export function
que noexport default
- Varios archivos que tienen lo mismo
export module Foo {
en el nivel superior (¡no piense que se combinarán en uno Foo
!)