A partir de ECMAScript 2015, JavaScript tiene un concepto de módulos. TypeScript comparte este concepto.

Los módulos se ejecutan dentro de su propio ámbito, no en el ámbito global; esto significa que las variables, funciones, clases, etc. declaradas en un módulo no son visibles fuera del módulo a menos que se exporten explícitamente usando uno de los export formas. Por el contrario, para consumir una variable, función, clase, interfaz, etc.exportada desde un módulo diferente, debe importarse utilizando uno de los import formas.

Los módulos son declarativos; las relaciones entre los módulos se especifican en términos de importaciones y exportaciones a nivel de archivo.

Los módulos se importan entre sí mediante un cargador de módulos. En tiempo de ejecución, el cargador de módulos es responsable de localizar y ejecutar todas las dependencias de un módulo antes de ejecutarlo. Los cargadores de módulos conocidos que se utilizan en JavaScript son el cargador de Node.js para CommonJS módulos y el RequireJS cargador para AMD módulos en aplicaciones web.

En TypeScript, al igual que en ECMAScript 2015, cualquier archivo que contenga un nivel superior import o export se considera un módulo. Por el contrario, un archivo sin ningún nivel superior import o export Las declaraciones se tratan como un script cuyo contenido está disponible en el ámbito global (y por lo tanto también en los módulos).

Exportar

Exportar una declaración

Cualquier declaración (como una variable, función, clase, alias de tipo o interfaz) se puede exportar agregando el export palabra clave.

StringValidator.ts
export interface StringValidator {
  isAcceptable(s: string): boolean;
}
ZipCodeValidator.ts
import { StringValidator } from "./StringValidator";

export const numberRegexp = /^[0-9]+$/;

export class ZipCodeValidator implements StringValidator {
  isAcceptable(s: string) {
    return s.length === 5 && numberRegexp.test(s);
  }
}

Exportar declaraciones

Las declaraciones de exportación son útiles cuando es necesario cambiar el nombre de las exportaciones para los consumidores, por lo que el ejemplo anterior se puede escribir como:

class ZipCodeValidator implements StringValidator {
  isAcceptable(s: string) {
    return s.length === 5 && numberRegexp.test(s);
  }
}
export { ZipCodeValidator };
export { ZipCodeValidator as mainValidator };

Reexportaciones

A menudo, los módulos amplían otros módulos y exponen parcialmente algunas de sus características. Una reexportación no lo importa localmente ni introduce una variable local.

ParseIntBasedZipCodeValidator.ts
export class ParseIntBasedZipCodeValidator {
  isAcceptable(s: string) {
    return s.length === 5 && parseInt(s).toString() === s;
  }
}

// Export original validator but rename it
export { ZipCodeValidator as RegExpBasedZipCodeValidator } from "./ZipCodeValidator";

Opcionalmente, un módulo puede envolver uno o más módulos y combinar todas sus exportaciones usando export * from "module" sintaxis.

AllValidators.ts
export * from "./StringValidator"; // exports 'StringValidator' interface
export * from "./ZipCodeValidator"; // exports 'ZipCodeValidator' class and 'numberRegexp' constant value
export * from "./ParseIntBasedZipCodeValidator"; //  exports the 'ParseIntBasedZipCodeValidator' class
// and re-exports 'RegExpBasedZipCodeValidator' as alias
// of the 'ZipCodeValidator' class from 'ZipCodeValidator.ts'
// module.

Importar

Importar es tan fácil como exportar desde un módulo. La importación de una declaración exportada se realiza mediante uno de los import formularios a continuación:

Importar una sola exportación de un módulo

import { ZipCodeValidator } from "./ZipCodeValidator";

let myValidator = new ZipCodeValidator();

las importaciones también se pueden renombrar

import { ZipCodeValidator as ZCV } from "./ZipCodeValidator";
let myValidator = new ZCV();

Importe todo el módulo en una sola variable y utilícelo para acceder a las exportaciones del módulo

import * as validator from "./ZipCodeValidator";
let myValidator = new validator.ZipCodeValidator();

Importar un módulo solo para efectos secundarios

Aunque no es una práctica recomendada, algunos módulos configuran un estado global que pueden utilizar otros módulos. Estos módulos pueden no tener exportaciones o el consumidor no está interesado en ninguna de sus exportaciones. Para importar estos módulos, use:

import "./my-module.js";

Importación de tipos

Antes de TypeScript 3.8, puede importar un tipo usando import. Con TypeScript 3.8, puede importar un tipo usando el import declaración, o usando import type.

// Re-using the same import
import { APIResponseType } from "./api";

// Explicitly use import type
import type { APIResponseType } from "./api";

import type siempre se garantiza que se eliminará de su JavaScript, y herramientas como Babel pueden hacer mejores suposiciones sobre su código a través del isolatedModules bandera del compilador. Puedes leer más en el 3.8 notas de la versión.

Exportaciones predeterminadas

Cada módulo puede exportar opcionalmente un default exportar. Las exportaciones predeterminadas están marcadas con la palabra clave default; y solo puede haber uno default exportar por módulo. default las exportaciones se importan utilizando un formulario de importación diferente.

default las exportaciones son realmente útiles. Por ejemplo, una biblioteca como jQuery puede tener una exportación predeterminada de jQuery o $, que probablemente también importaríamos con el nombre $ o jQuery.

JQuery.d.ts
declare let $: JQuery;
export default $;
App.ts
import $ from "jquery";

$("button.continue").html("Next Step...");

Las clases y declaraciones de funciones se pueden crear directamente como exportaciones predeterminadas. Los nombres de declaración de funciones y clases de exportación predeterminados son opcionales.

ZipCodeValidator.ts
export default class ZipCodeValidator {
  static numberRegexp = /^[0-9]+$/;
  isAcceptable(s: string) {
    return s.length === 5 && ZipCodeValidator.numberRegexp.test(s);
  }
}
Test.ts
import validator from "./ZipCodeValidator";

let myValidator = new validator();

o

StaticZipCodeValidator.ts
const numberRegexp = /^[0-9]+$/;

export default function (s: string) {
  return s.length === 5 && numberRegexp.test(s);
}
Test.ts
import validate from "./StaticZipCodeValidator";

let strings = ["Hello", "98052", "101"];

// Use function validate
strings.forEach((s) => {
  console.log(`"${s}" ${validate(s) ? "matches" : "does not match"}`);
});

default las exportaciones también pueden ser solo valores:

OneTwoThree.ts
export default "123";
Log.ts
import num from "./OneTwoThree";

console.log(num); // "123"

Exportar todo como x

Con TypeScript 3.8, puede utilizar export * as ns como una forma abreviada de volver a exportar otro módulo con un nombre:

export * as utilities from "./utilities";

Esto toma todas las dependencias de un módulo y lo convierte en un campo exportado, podría importarlo así:

import { utilities } from "./index";

export = y import = require()

Tanto CommonJS como AMD generalmente tienen el concepto de un exports objeto que contiene todas las exportaciones de un módulo.

También apoyan la sustitución del exports objeto con un único objeto personalizado. Las exportaciones predeterminadas están destinadas a reemplazar este comportamiento; sin embargo, los dos son incompatibles. Soporta TypeScript export = para modelar el flujo de trabajo tradicional de CommonJS y AMD.

los export = la sintaxis especifica un único objeto que se exporta desde el módulo. Puede ser una clase, interfaz, espacio de nombres, función o enumeración.

Al exportar un módulo usando export =, Específico de TypeScript import module = require("module") debe utilizarse para importar el módulo.

ZipCodeValidator.ts
let numberRegexp = /^[0-9]+$/;
class ZipCodeValidator {
  isAcceptable(s: string) {
    return s.length === 5 && numberRegexp.test(s);
  }
}
export = ZipCodeValidator;
Test.ts
import zip = require("./ZipCodeValidator");

// Some samples to try
let strings = ["Hello", "98052", "101"];

// Validators to use
let validator = new zip();

// Show whether each string passed each validator
strings.forEach((s) => {
  console.log(
    `"${s}" - ${validator.isAcceptable(s) ? "matches" : "does not match"}`
  );
});

Generación de código para módulos

Dependiendo del destino del módulo especificado durante la compilación, el compilador generará el código apropiado para Node.js (CommonJS), require.js (AMD), UMD, SystemJS, o Módulos nativos de ECMAScript 2015 (ES6) sistemas de carga de módulos. Para obtener más información sobre lo que define, require y register las llamadas en el código generado sí, consulte la documentación de cada cargador de módulo.

Este sencillo ejemplo muestra cómo los nombres utilizados durante la importación y exportación se traducen al código de carga del módulo.

SimpleModule.ts
import m = require("mod");
export let t = m.something + 1;
AMD / RequireJS SimpleModule.js
define(["require", "exports", "./mod"], function (require, exports, mod_1) {
  exports.t = mod_1.something + 1;
});
CommonJS / Node SimpleModule.js
var mod_1 = require("./mod");
exports.t = mod_1.something + 1;
UMD SimpleModule.js
(function (factory) {
  if (typeof module === "object" && typeof module.exports === "object") {
    var v = factory(require, exports);
    if (v !== undefined) module.exports = v;
  } else if (typeof define === "function" && define.amd) {
    define(["require", "exports", "./mod"], factory);
  }
})(function (require, exports) {
  var mod_1 = require("./mod");
  exports.t = mod_1.something + 1;
});
Sistema SimpleModule.js
System.register(["./mod"], function (exports_1) {
  var mod_1;
  var t;
  return {
    setters: [
      function (mod_1_1) {
        mod_1 = mod_1_1;
      },
    ],
    execute: function () {
      exports_1("t", (t = mod_1.something + 1));
    },
  };
});
Módulos nativos de ECMAScript 2015 SimpleModule.js
import { something } from "./mod";
export var t = something + 1;

Ejemplo simple

A continuación, hemos consolidado las implementaciones de Validator utilizadas en ejemplos anteriores para exportar solo una exportación con nombre de cada módulo.

Para compilar, debemos especificar un destino de módulo en la línea de comando. Para Node.js, use --module commonjs; para require.js, usa --module amd. Por ejemplo:

tsc --module commonjs Test.ts

Cuando se compile, cada módulo se convertirá en un .js expediente. Al igual que con las etiquetas de referencia, el compilador seguirá import declaraciones para compilar archivos dependientes.

Validation.ts
export interface StringValidator {
  isAcceptable(s: string): boolean;
}
LettersOnlyValidator.ts
import { StringValidator } from "./Validation";

const lettersRegexp = /^[A-Za-z]+$/;

export class LettersOnlyValidator implements StringValidator {
  isAcceptable(s: string) {
    return lettersRegexp.test(s);
  }
}
ZipCodeValidator.ts
import { StringValidator } from "./Validation";

const numberRegexp = /^[0-9]+$/;

export class ZipCodeValidator implements StringValidator {
  isAcceptable(s: string) {
    return s.length === 5 && numberRegexp.test(s);
  }
}
Test.ts
import { StringValidator } from "./Validation";
import { ZipCodeValidator } from "./ZipCodeValidator";
import { LettersOnlyValidator } from "./LettersOnlyValidator";

// Some samples to try
let strings = ["Hello", "98052", "101"];

// Validators to use
let validators: { [s: string]: StringValidator } = {};
validators["ZIP code"] = new ZipCodeValidator();
validators["Letters only"] = new LettersOnlyValidator();

// Show whether each string passed each validator
strings.forEach((s) => {
  for (let name in validators) {
    console.log(
      `"${s}" - ${
        validators[name].isAcceptable(s) ? "matches" : "does not match"
      } ${name}`
    );
  }
});

Carga de módulos opcionales y otros escenarios de carga avanzados

En algunos casos, es posible que desee cargar un módulo solo en determinadas condiciones. En TypeScript, podemos usar el patrón que se muestra a continuación para implementar este y otros escenarios de carga avanzados para invocar directamente los cargadores de módulos sin perder la seguridad de los tipos.

El compilador detecta si cada módulo se utiliza en el JavaScript emitido. Si un identificador de módulo solo se usa como parte de anotaciones de tipo y nunca como una expresión, entonces no require se emite una llamada para ese módulo. Esta elisión de referencias no utilizadas es una buena optimización del rendimiento y también permite la carga opcional de esos módulos.

La idea central del patrón es que el import id = require("...") declaración nos da acceso a los tipos expuestos por el módulo. Se invoca el cargador de módulos (a través de require) dinámicamente, como se muestra en la if cuadras abajo. Esto aprovecha la optimización de elisión de referencia para que el módulo solo se cargue cuando sea necesario. Para que este patrón funcione, es importante que el símbolo definido mediante un import sólo se utiliza en posiciones de tipo (es decir, nunca en una posición que se emitiría en JavaScript).

Para mantener la seguridad de los tipos, podemos utilizar el typeof palabra clave. los typeof La palabra clave, cuando se usa en una posición de tipo, produce el tipo de un valor, en este caso el tipo del módulo.

Carga dinámica de módulos en Node.js
declare function require(moduleName: string): any;

import { ZipCodeValidator as Zip } from "./ZipCodeValidator";

if (needZipValidation) {
  let ZipCodeValidator: typeof Zip = require("./ZipCodeValidator");
  let validator = new ZipCodeValidator();
  if (validator.isAcceptable("...")) {
    /* ... */
  }
}
Ejemplo: carga dinámica de módulos en require.js
declare function require(
  moduleNames: string[],
  onLoad: (...args: any[]) => void
): void;

import * as Zip from "./ZipCodeValidator";

if (needZipValidation) {
  require(["./ZipCodeValidator"], (ZipCodeValidator: typeof Zip) => {
    let validator = new ZipCodeValidator.ZipCodeValidator();
    if (validator.isAcceptable("...")) {
      /* ... */
    }
  });
}
Ejemplo: carga dinámica de módulos en System.js
declare const System: any;

import { ZipCodeValidator as Zip } from "./ZipCodeValidator";

if (needZipValidation) {
  System.import("./ZipCodeValidator").then((ZipCodeValidator: typeof Zip) => {
    var x = new ZipCodeValidator();
    if (x.isAcceptable("...")) {
      /* ... */
    }
  });
}

Trabajar con otras bibliotecas de JavaScript

Para describir la forma de las bibliotecas que no están escritas en TypeScript, necesitamos declarar la API que expone la biblioteca.

Llamamos “ambiente” a las declaraciones que no definen una implementación. Normalmente, estos se definen en .d.ts archivos. Si está familiarizado con C / C ++, puede pensar en ellos como .h archivos. Veamos algunos ejemplos.

Módulos ambientales

En Node.js, la mayoría de las tareas se realizan cargando uno o más módulos. Podríamos definir cada módulo en su propio .d.ts archivo con declaraciones de exportación de nivel superior, pero es más conveniente escribirlos como uno más grande .d.ts expediente. Para hacerlo, usamos una construcción similar a los espacios de nombres ambientales, pero usamos la module palabra clave y el nombre entre comillas del módulo que estará disponible para una importación posterior. Por ejemplo:

node.d.ts (extracto simplificado)
declare module "url" {
  export interface Url {
    protocol?: string;
    hostname?: string;
    pathname?: string;
  }

  export function parse(
    urlStr: string,
    parseQueryString?,
    slashesDenoteHost?
  ): Url;
}

declare module "path" {
  export function normalize(p: string): string;
  export function join(...paths: any[]): string;
  export var sep: string;
}

Ahora podemos /// <reference> node.d.ts y luego cargue los módulos usando import url = require("url"); o import * as URL from "url".

/// <reference path="node.d.ts"/>
import * as URL from "url";
let myUrl = URL.parse("http://www.typescriptlang.org");

Módulos ambientales taquigráficos

Si no desea tomarse el tiempo para escribir declaraciones antes de usar un nuevo módulo, puede usar una declaración abreviada para comenzar rápidamente.

declaraciones.d.ts
declare module "hot-new-module";

Todas las importaciones de un módulo de taquigrafía tendrán la any escribe.

import x, { y } from "hot-new-module";
x(y);

Declaraciones de módulos comodín

Algunos cargadores de módulos como SystemJS y AMD permitir que se importe contenido que no sea JavaScript. Estos suelen utilizar un prefijo o sufijo para indicar la semántica de carga especial. Las declaraciones de módulos comodín se pueden utilizar para cubrir estos casos.

declare module "*!text" {
  const content: string;
  export default content;
}
// Some do it the other way around.
declare module "json!*" {
  const value: any;
  export default value;
}

Ahora puedes importar cosas que coincidan "*!text" o "json!*".

import fileContent from "./xyz.txt!text";
import data from "json!http://example.com/data.json";
console.log(data, fileContent);

Módulos UMD

Algunas bibliotecas están diseñadas para usarse en muchos cargadores de módulos o sin carga de módulos (variables globales). Estos se conocen como UMD módulos. Se puede acceder a estas bibliotecas mediante una importación o una variable global. Por ejemplo:

math-lib.d.ts
export function isPrime(x: number): boolean;
export as namespace mathLib;

Luego, la biblioteca se puede usar como una importación dentro de los módulos:

import { isPrime } from "math-lib";
isPrime(2);
mathLib.isPrime(2); // ERROR: can't use the global definition from inside a module

También se puede utilizar como variable global, pero solo dentro de un script. (Un script es un archivo sin importaciones ni exportaciones).

mathLib.isPrime(2);

Orientación para estructurar módulos

Exportar lo más cerca posible del nivel superior

Los consumidores de su módulo deben tener la menor fricción posible al usar los elementos que exporta. Agregar demasiados niveles de anidación tiende a ser engorroso, así que piense detenidamente cómo desea estructurar las cosas.

Exportar un espacio de nombres desde su módulo es un ejemplo de cómo agregar demasiadas capas de anidación. Si bien los espacios de nombres a veces tienen sus usos, agregan un nivel adicional de direccionamiento indirecto cuando se usan módulos. Esto puede convertirse rápidamente en un problema para los usuarios y, por lo general, no es necesario.

Los métodos estáticos en una clase exportada tienen un problema similar: la propia clase agrega una capa de anidamiento. A menos que aumente la expresividad o la intención de una manera claramente útil, considere simplemente exportar una función de ayuda.

Si solo está exportando una class o function, usar export default

Así como “exportar cerca del nivel superior” reduce la fricción en su los consumidores del módulo, también lo hace la introducción de una exportación predeterminada. Si el propósito principal de un módulo es albergar una exportación específica, entonces debería considerar exportarlo como una exportación predeterminada. Esto hace que tanto la importación como el uso real de la importación sean un poco más fáciles. Por ejemplo:

MyClass.ts

export default class SomeType {
  constructor() { ... }
}

MyFunc.ts

export default function getThing() {
  return "thing";
}

Consumer.ts

import t from "./MyClass";
import f from "./MyFunc";
let x = new t();
console.log(f());

Esto es óptimo para los consumidores. Pueden nombrar tu tipo como quieran (t en este caso) y no tiene que hacer un exceso de puntos para encontrar sus objetos.

Si está exportando varios objetos, colóquelos todos en el nivel superior

MisCosas.ts

export class SomeType {
  /* ... */
}
export function someFunc() {
  /* ... */
}

A la inversa, al importar:

Enumere explícitamente los nombres importados

Consumer.ts

import { SomeType, someFunc } from "./MyThings";
let x = new SomeType();
let y = someFunc();

Utilice el patrón de importación del espacio de nombres si está importando una gran cantidad de cosas

MyLargeModule.ts

export class Dog { ... }
export class Cat { ... }
export class Tree { ... }
export class Flower { ... }

Consumer.ts

import * as myLargeModule from "./MyLargeModule.ts";
let x = new myLargeModule.Dog();

Reexportar para ampliar

A menudo, necesitará ampliar la funcionalidad de un módulo. Un patrón JS común es aumentar el objeto original con extensiones, similar a cómo funcionan las extensiones de JQuery. Como mencionamos antes, los módulos no unir como lo harían los objetos de espacio de nombres globales. La solución recomendada es no mute el objeto original, sino que exporte una nueva entidad que proporcione la nueva funcionalidad.

Considere una implementación de calculadora simple definida en el módulo Calculator.ts. El módulo también exporta una función auxiliar para probar la funcionalidad de la calculadora pasando una lista de cadenas de entrada y escribiendo el resultado al final.

Calculator.ts

export class Calculator {
  private current = 0;
  private memory = 0;
  private operator: string;

  protected processDigit(digit: string, currentValue: number) {
    if (digit >= "0" && digit <= "9") {
      return currentValue * 10 + (digit.charCodeAt(0) - "0".charCodeAt(0));
    }
  }

  protected processOperator(operator: string) {
    if (["+", "-", "*", "https://foroayuda.es/"].indexOf(operator) >= 0) {
      return operator;
    }
  }

  protected evaluateOperator(
    operator: string,
    left: number,
    right: number
  ): number {
    switch (this.operator) {
      case "+":
        return left + right;
      case "-":
        return left - right;
      case "*":
        return left * right;
      case "https://foroayuda.es/":
        return left / right;
    }
  }

  private evaluate() {
    if (this.operator) {
      this.memory = this.evaluateOperator(
        this.operator,
        this.memory,
        this.current
      );
    } else {
      this.memory = this.current;
    }
    this.current = 0;
  }

  public handleChar(char: string) {
    if (char === "=") {
      this.evaluate();
      return;
    } else {
      let value = this.processDigit(char, this.current);
      if (value !== undefined) {
        this.current = value;
        return;
      } else {
        let value = this.processOperator(char);
        if (value !== undefined) {
          this.evaluate();
          this.operator = value;
          return;
        }
      }
    }
    throw new Error(`Unsupported input: '${char}'`);
  }

  public getResult() {
    return this.memory;
  }
}

export function test(c: Calculator, input: string) {
  for (let i = 0; i < input.length; i++) {
    c.handleChar(input[i]);
  }

  console.log(`result of '${input}' is '${c.getResult()}'`);
}

Aquí hay una prueba simple para la calculadora que usa los datos expuestos. test función.

TestCalculator.ts

import { Calculator, test } from "./Calculator";

let c = new Calculator();
test(c, "1+2*33/11="); // prints 9

Ahora, para extender esto y agregar soporte para la entrada con números en bases distintas de 10, creemos ProgrammerCalculator.ts

ProgrammerCalculator.ts

import { Calculator } from "./Calculator";

class ProgrammerCalculator extends Calculator {
  static digits = [
    "0",
    "1",
    "2",
    "3",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9",
    "A",
    "B",
    "C",
    "D",
    "E",
    "F",
  ];

  constructor(public base: number) {
    super();
    const maxBase = ProgrammerCalculator.digits.length;
    if (base <= 0 || base > maxBase) {
      throw new Error(`base has to be within 0 to ${maxBase} inclusive.`);
    }
  }

  protected processDigit(digit: string, currentValue: number) {
    if (ProgrammerCalculator.digits.indexOf(digit) >= 0) {
      return (
        currentValue * this.base + ProgrammerCalculator.digits.indexOf(digit)
      );
    }
  }
}

// Export the new extended calculator as Calculator
export { ProgrammerCalculator as Calculator };

// Also, export the helper function
export { test } from "./Calculator";

El nuevo módulo ProgrammerCalculator exporta una forma de API similar a la del original Calculator módulo, pero no aumenta ningún objeto en el módulo original. Aquí hay una prueba para nuestra clase ProgrammerCalculator:

TestProgrammerCalculator.ts

import { Calculator, test } from "./ProgrammerCalculator";

let c = new Calculator(2);
test(c, "001+010="); // prints 3

No use espacios de nombres en módulos

Cuando se cambia por primera vez a una organización basada en módulos, una tendencia común es envolver las exportaciones en una capa adicional de espacios de nombres. Los módulos tienen su propio alcance y solo las declaraciones exportadas son visibles desde fuera del módulo. Teniendo esto en cuenta, el espacio de nombres proporciona muy poco valor, si es que lo hay, cuando se trabaja con módulos.

En el frente de la organización, los espacios de nombres son útiles para agrupar objetos y tipos relacionados lógicamente en el ámbito global. Por ejemplo, en C #, encontrará todos los tipos de colección en System.Collections. Al organizar nuestros tipos en espacios de nombres jerárquicos, proporcionamos una buena experiencia de “descubrimiento” para los usuarios de esos tipos. Los módulos, por otro lado, 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 de organización lógico que podemos usar. Podemos tener una carpeta / collections / generic / con un módulo de lista en ella.

Los espacios de nombres son importantes para evitar colisiones de nombres en el ámbito global. Por ejemplo, podrías tener My.Application.Customer.AddForm y My.Application.Order.AddForm : Dos tipos con el mismo nombre, pero con un espacio de nombres diferente. Sin embargo, esto no es un problema con los módulos. Dentro de un módulo, no hay ninguna razón plausible para tener dos objetos con el mismo nombre. Desde el punto de vista del consumo, el consumidor de cualquier módulo puede elegir el nombre que usará para referirse al módulo, por lo que los conflictos de nombres accidentales son imposibles.

Para obtener más información sobre módulos y espacios de nombres, consulte Espacios de nombres y módulos.

Banderas rojas

Todas las siguientes son señales de alerta para la estructuración de módulos. Vuelva a verificar que no está intentando asignar un espacio de nombres 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 namespace Foo { ... } (retirar Foo y mover todo ‘arriba’ un nivel)
  • Varios archivos que tienen el mismo export namespace Foo { en el nivel superior (no crea que estos se van a combinar en uno Foo!)