Sistema de módulos de TypeScript

El sistema de módulos es la base del desarrollo moderno de TypeScript.

TypeScript es totalmente compatible con la sintaxis de ES Module y ofrece una amplia variedad de estrategias de resolución de módulos.

Mediante el sistema de módulos, se puede dividir el código en unidades reutilizables, logrando organización y reutilización del código.


Diagrama SVG: exportación e importación de módulos Fondo Título Flujo de exportación e importación de módulos Módulo user.ts user.ts export const name = "Alice" export class User { ... } export interface Config { ... Flecha import Módulo main.ts main.ts import { name, User } from "./user"; import User from "./user" Flecha use Runtime Resultado de ejecución JavaScript Ejecutar código Parte inferior: tipos de exportación Formas de exportación e importación Forma 1 Exportación/importación con nombre Forma 2 Exportación/importación por defecto Forma 3 Re-exportación Forma 4 Importación dinámica Marcador de flecha

¿Por qué se necesita un sistema de módulos?

A medida que crece el tamaño del proyecto, la cantidad de código aumenta cada vez más.

Al distribuir el código en múltiples archivos y organizarlo mediante módulos, se puede mejorar la mantenibilidad y la reutilización del código.

El sistema de módulos hace que cada archivo tenga su propio ámbito, evitando la contaminación de variables globales.

Explicación del concepto:Un módulo es un archivo de TypeScript que contiene sentencias de exportación e importación. El contenido se exporta mediante `export` y se importa mediante `import`.


Exportación de módulos

Con la palabra clave `export` se pueden exportar variables, funciones, clases, interfaces, etc., para que otros módulos las utilicen.

Módulo user.ts

// Exportar variable
export var name = "Alice";
export const age = 25;

// Exportar función
export function greet(message: string): string {
    return "Hello, " + message;
}

// Exportar clase
export class User {
    // Propiedades de parámetros del constructor
    constructor(public name: string) {}

    // Método de presentación
    introduce(): string {
        return "I am " + this.name;
    }
}

// Exportar interfaz (la interfaz desaparece tras la compilación, solo se usa para la verificación de tipos)
export interface Config {
    // Configurar host
    host: string;
    // Configurar puerto
    port: number;
}

// Exportación por lotes: exportación con renombrado
export { name as userName, age as userAge };

Nota:Las interfaces y los tipos no generan código real en el JavaScript compilado; solo se utilizan para la verificación de tipos de TypeScript.


Importación de módulos

Usa la palabra clave `import` para importar el contenido exportado desde otros módulos.

main.ts importa el módulo

// Importación con nombre: importa contenido específico del módulo
import { name, age, greet } from "./user";

// Importación por defecto: importa la exportación por defecto del módulo
import User from "./user";

// Importación total: coloca todas las exportaciones del módulo en un objeto
import * as UserModule from "./user";

// Importación con renombrado: evita conflictos de nombres
import { greet as sayHello } from "./user";

// Usar el contenido importado
console.log(greet("World"));
console.log(sayHello("TypeScript"));

Resultado de ejecución:

Hello, World
Hello, TypeScript

Explicación de rutas:La ruta de importación puede ser una ruta relativa (como./user) o una ruta absoluta (como@/utils)。


Exportación por defecto

Cada módulo puede tener una exportación por defecto.

La exportación por defecto no requiere llaves al importarse y se le puede asignar cualquier nombre.

Módulo math.ts

// Exportación por defecto: un módulo solo puede tener una exportación por defecto
export default function add(a: number, b: number): number {
    return a + b;
}

// Se puede combinar con otras exportaciones
export function multiply(a: number, b: number): number {
    return a * b;
}

Importación en main.ts

// Importar la exportación por defecto: se le puede dar cualquier nombre
import add from "./math";

// Importar exportaciones con nombre: se requieren llaves
import { multiply } from "./math";

console.log("Suma: " + add(2, 3));
console.log("Multiplicación: " + multiply(4, 5));

Resultado de ejecución:

加法: 5
乘法: 20

Sugerencia:Para el contenido principal de exportación, como funciones de utilidad y clases, usa la exportación por defecto; para funciones auxiliares, interfaces, etc., usa exportaciones con nombre.


Re-exportación

La re-exportación (Re-export) se utiliza para agregar el contenido de múltiples módulos, o para exponer las exportaciones de un módulo a otro.

Módulo agregador index.ts

// Re-exportar contenido específico desde otros módulos
export { name, age } from "./user";

// Re-exportar la exportación por defecto (requiere renombrar)
export { default as User } from "./user";

// Re-exportar todo el contenido
export * from "./math";

Casos de uso:Usa index.ts como archivo de entrada para exportar de forma centralizada el contenido de los submódulos, facilitando la importación unificada.


Estrategia de resolución de módulos

TypeScript ofrece múltiples estrategias de resolución de módulos para localizar los módulos importados.

Se puede configurar en tsconfig.json.

Configuración de tsconfig.json

{
    "compilerOptions": {
        // Estrategia de resolución de Node
        // Sigue las reglas de resolución de módulos de Node.js
        "moduleResolution": "node",

        // Estrategia de resolución clásica
        // Estrategia utilizada en versiones tempranas de TypeScript
        "moduleResolution": "classic",

        // baseUrl: establece la ruta base
        // Todas las importaciones de rutas no relativas se resuelven a partir de esta ruta
        "baseUrl": "./src",

        // Mapeo de rutas: establece alias para las rutas de importación
        "paths": {
            // Las importaciones que comienzan con @ se mapean al directorio src
            "@/*": ["./*"],
            // Las importaciones que comienzan con @components se mapean al directorio components
            "@components/*": ["./components/*"]
        }
    }
}

Sugerencia de configuración:Para proyectos nuevos se recomienda usar la estrategia de resolución de Node, que es actualmente la más utilizada.


Importación dinámica

La importación dinámica (Dynamic Import) utiliza la sintaxis `import()` y permite cargar módulos bajo demanda en tiempo de ejecución.

Esto es muy útil para la división de código y la carga diferida (lazy loading).

Ejemplo

// Importación dinámica - carga diferida
// import() devuelve una Promise
async function loadMath() {
    // Importación dinámica del módulo: solo se carga al ejecutar esta línea
    var math = await import("./math");

    // math.default es la función exportada por defecto
    console.log("Suma dinámica: " + math.default(1, 2));
}

// Llamar a la función de carga diferida
loadMath();

// Importación condicional: carga dinámicamente diferentes módulos según la condición
async function loadFeature(enable: boolean) {
    if (enable) {
        // Solo se carga el módulo cuando se cumple la condición
        var feature = await import("./feature");
        feature.run();
    }
}

// Cargar según la condición
loadFeature(true);

Resultado de ejecución:

动态加法: 3

Optimización del rendimiento:La importación dinámica permite la división de código, cargando código adicional solo cuando se necesita, lo que reduce el tiempo de carga inicial.


Consideraciones

  • Rutas relativas:Usa rutas relativas para importar módulos locales (./, ../)
  • Extensión de módulos:TypeScript maneja automáticamente las extensiones durante la compilación
  • Por defecto vs. con nombre:Cada módulo tiene una exportación por defecto y múltiples exportaciones con nombre
  • esModuleInterop:Habilitar esta opción facilita la importación de módulos CommonJS

Mejores prácticas:Mantén las rutas de importación coherentes, usa alias de ruta para simplificar rutas largas y establece una estructura de organización de módulos clara.


Resumen

El sistema de módulos es el núcleo de la organización de proyectos TypeScript.

  • export:Exportar variables, funciones, clases e interfaces
  • import:Importar el contenido exportado
  • Exportación por defecto:Una por módulo, de uso flexible
  • Re-exportación:Agregar módulos, crear archivos de entrada
  • Importación dinámica:Carga diferida, optimizar el rendimiento
  • Resolución de módulos:Configurar alias de ruta y estrategias de resolución

Sugerencia:Organiza razonablemente la estructura de módulos, usa alias de ruta para simplificar las importaciones y establece normas claras de exportación e importación.

Otras extensiones