Namespaces en TypeScript: qué son y cuándo existían antes de los módulos ES. La historia: cómo los namespaces eran la forma de organizar código antes de los import. Por qué hoy debes usar módulos ES y no namespaces. El único caso de uso válido actual: fic

Antes de que existieran los módulos ES, TypeScript introdujo los namespaces como mecanismo para organizar código en espacios de nombres y evitar colisiones de nombres globales. En 2026 los namespaces son una característica obsoleta para código de aplicación, pero siguen siendo la herramienta correcta en un contexto muy específico: los ficheros de declaración ambient para librerías que exponen globales.

La historia: organizar código antes de los módulos

En los primeros años de TypeScript (2012-2014), los proyectos web concatenaban ficheros JavaScript sin sistema de módulos. Los namespaces (entonces llamados "módulos internos") permitían agrupar código bajo un nombre para evitar contaminar el scope global:

// Sintaxis antigua con namespace (no uses esto en código nuevo)
namespace MiApp {
  export interface Usuario {
    id: number;
    nombre: string;
  }

  export function saludar(u: Usuario): string {
    return `Hola, ${u.nombre}`;
  }

  export namespace Utilidades {
    export function formatear(fecha: Date): string {
      return fecha.toISOString();
    }
  }
}

// Uso:
const u: MiApp.Usuario = { id: 1, nombre: "Ana" };
MiApp.saludar(u);
MiApp.Utilidades.formatear(new Date());

Por qué hoy debes usar módulos ES

Los módulos ES (ESM) resuelven el mismo problema de forma más limpia y estándar. Cada fichero es su propio módulo con su propio scope. Las importaciones son explícitas. El código es analizable por bundlers para tree-shaking. El ecosistema completo de JavaScript (Node.js, navegadores, Deno, Bun) soporta ESM de forma nativa.

Los namespaces en código de aplicación generan código JavaScript con objetos anidados que los bundlers modernos no pueden optimizar bien. No hay ventaja técnica sobre los módulos ES y sí hay desventajas claras.

El único caso de uso válido: ficheros .d.ts de ambient declarations

Los namespaces siguen siendo la herramienta correcta para describir librerías antiguas que exponen objetos en el scope global, como jQuery, Google Analytics o librerías UMD que añaden propiedades a window:

// types/jquery/index.d.ts
declare namespace jQuery {
  function ajax(url: string, opciones?: AjaxOptions): Promise;
  function get(url: string): Promise;

  interface AjaxOptions {
    method?: "GET" | "POST" | "PUT" | "DELETE";
    data?: unknown;
    headers?: Record;
  }
}

declare const $: typeof jQuery;
// types/google-analytics/index.d.ts
declare namespace gtag {
  function (comando: "event", nombre: string, params?: Record): void;
  function (comando: "config", id: string, params?: Record): void;
}

declare function gtag(...args: unknown[]): void;

Cómo migrar de namespaces a módulos

Si tienes un proyecto heredado con namespaces, la migración a módulos ES es directa:

  • Añade export a las declaraciones que quieres exponer fuera del fichero.
  • Elimina el bloque namespace NombreApp { ... } que lo envuelve.
  • Sustituye los usos de NombreApp.Cosa por imports explícitos: import { Cosa } from "./fichero".
  • Configura "module": "ESNext" o "NodeNext" en tsconfig si no lo está ya.
// Antes (namespace)
namespace MiApp {
  export interface Config { debug: boolean }
  export function iniciar(cfg: Config): void { /* ... */ }
}

// Después (módulo ES)
export interface Config { debug: boolean }
export function iniciar(cfg: Config): void { /* ... */ }

La migración de namespaces a módulos normalmente no cambia la lógica de la aplicación, solo la forma en que el código se organiza y se importa. El resultado es código más moderno, compatible con herramientas actuales y mejor analizable por bundlers.

Imagen: Pexels / Myburgh Roux

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP