Saltar al contenido
Aback Tools Logo

Error TS1384 de TypeScript: causa y solución

Soluciona el error TS1384 de TypeScript («el modificador export no se puede aplicar a una ampliación de módulo»). Aprende las tres causas, el arreglo con export {}, isolatedModules y patrones .d.ts.

DH
Tutorials & How-Tos11 min de lectura2,650 palabras

El error TS1384 de TypeScript es uno de esos errores que parecen crípticos la primera vez que los ves, pero que siempre tienen una causa precisa y solucionable. Aparece cuando el compilador encuentra un modificador export en un lugar donde no puede estar legalmente, concretamente dentro de un bloque de ampliación de módulo. Esta guía explica exactamente qué significa TS1384, repasa todos los escenarios que lo provocan y te da la solución correcta para cada uno.

TS1384Código de errorExport en ampliación de módulo
1 líneaArreglo típicoexport {} resuelve la mayoría de casos
3Causas raízScript, isolatedModules, .d.ts

¿Qué es TS1384?

El error TS1384 de TypeScript lleva el mensaje: «el modificador "export" no se puede aplicar a una ampliación de módulo». Aparece cuando el compilador encuentra una palabra clave `export` dentro de un bloque `declare module` o `declare global`, las dos construcciones que TypeScript usa para la ampliación de módulos. Los bloques de ampliación sirven para extender los tipos de módulos existentes, no para declarar símbolos públicos nuevos, así que `export` es estructuralmente inválido dentro de ellos.

La ampliación de módulo en una frase

La ampliación de módulo es el mecanismo de TypeScript que te permite añadir miembros nuevos a los tipos de un módulo existente: por ejemplo, añadir una propiedad personalizada a `Express.Request`, extender `Window` con un global de terceros o añadir métodos a las opciones de componentes de un framework. La sintaxis se parece a un bloque `declare module 'nombre-del-módulo' {}` y debe estar en un archivo de módulo (un archivo con al menos una sentencia `import` o `export` de nivel superior).

  • TS1384 es un error del compilador: el archivo no pasará la comprobación de tipos hasta que se arregle
  • No afecta al tiempo de ejecución: el error es puramente de declaraciones de tipo
  • Es determinista: el mismo código siempre lo provoca; no hay versiones intermitentes
  • Tiene un conjunto reducido de causas raíz: contexto de script frente a módulo, isolatedModules y una estructura incorrecta de .d.ts cubren el 95 % de los casos

Note

TS1384 está relacionado con TS2669 («las ampliaciones del ámbito global solo pueden anidarse directamente en módulos externos o declaraciones de módulo ambiente»), pero es distinto. Ambos derivan de un contexto de archivo incorrecto para la sintaxis de ampliación y ambos se arreglan con la misma técnica de `export {}`; sin embargo, TS2669 surge por la ubicación del bloque `declare global`, mientras que TS1384 surge concretamente por un modificador `export` dentro de la ampliación.

Cuándo se produce TS1384

El error siempre implica un `export` en un lugar donde TypeScript no lo permite. Hay tres patrones distintos que lo producen, e identificar cuál se aplica a tu código determina la solución correcta.

Patrón 1: export dentro de un bloque declare module

El detonante más directo: escribes una sentencia `export` dentro de una ampliación `declare module`. Normalmente la intención es añadir algo a la API pública del módulo, pero los bloques de ampliación no funcionan así: solo pueden extender declaraciones de tipo que ya existen en el módulo de destino.

typescript
// ✗ TS1384 - export dentro de una ampliación de módulo
declare module 'some-library' {
  export interface NewInterface {   // <-- TS1384 aparece aquí
    id: string;
  }
}

// ✓ Correcto - interfaz añadida sin export
declare module 'some-library' {
  interface ExistingInterface {
    newProperty: string;            // extiende el tipo existente
  }
}

Patrón 2: el archivo se trata como script, no como módulo

Esta es la causa más común de TS1384 en proyectos reales. Si un archivo no tiene sentencias `import` o `export` de nivel superior, TypeScript lo trata como un script con ámbito global. Un bloque `declare global {}` en un archivo de script no tiene sentido (los globales ya son globales en los scripts), así que TypeScript rechaza cualquier `export` dentro de él con TS1384. El archivo debe ser un módulo para que el contexto de ampliación tenga sentido.

Patrón 3: estructura incorrecta del archivo .d.ts

Los archivos de declaración (`.d.ts`) que mezclan declaraciones de módulo ambiente con sentencias `export` normales en el orden equivocado pueden provocar TS1384. Un `.d.ts` que empieza con declaraciones `export` de nivel superior y luego contiene un bloque `declare module` se trata como módulo, lo cual es correcto. Pero un `.d.ts` que envuelve todo dentro de un único bloque `declare module` y luego intenta usar `export` dentro de ese bloque confunde el contexto de ampliación con un contexto de definición de módulo.

Warning

TS1384 también puede originarse en un **paquete de terceros** que distribuye archivos `.d.ts` rotos. Si el error señala una ruta dentro de `node_modules`, el origen es una dependencia, no tu código. En ese caso la solución es `skipLibCheck: true` en tsconfig.json, no modificar los archivos del paquete.

Cómo arreglar TS1384: ampliación de módulo

La solución correcta depende de lo que realmente intentas conseguir. Hay dos objetivos distintos que pueden llevar a TS1384 y requieren enfoques diferentes. Sigue estos cuatro pasos para resolver el error de forma limpia.

1

Identifica qué patrón provoca TS1384

Lee con atención el error completo del compilador. Fíjate en la extensión del archivo (.ts o .d.ts), el número de línea y si el `export` está dentro de un bloque `declare module`, un bloque `declare global` o en otro sitio. El contexto del código circundante te dirá cuál de los tres patrones anteriores se aplica. Si la ruta del error empieza por `node_modules/`, salta a la solución con `skipLibCheck`: los otros patrones no aplican.

2

Añade export {} para convertir el archivo en módulo

Si tu archivo tiene un bloque `declare module` o `declare global` pero no tiene importaciones ni exportaciones de nivel superior, añade `export {}` al principio. Esta sola línea convierte el archivo de contexto de script a contexto de módulo, el entorno necesario para la sintaxis de ampliación. La exportación vacía no añade nada al resultado compilado: es puramente una señal de contexto para TypeScript.

src/types/global.d.ts
typescript
// Añade esta línea para convertir el archivo en módulo
export {};

declare global {
  interface Window {
    myAnalytics: AnalyticsInstance;
  }
}
3

Mueve declare global a un módulo existente

Una alternativa a añadir `export {}` es colocar el bloque `declare global` dentro de un archivo que ya tenga importaciones o exportaciones reales, como el punto de entrada de una librería, un módulo de funcionalidad o un archivo de utilidades compartidas. Este enfoque mantiene tus ampliaciones de tipo junto al código que extienden, lo que puede ser más fácil de mantener que un archivo de declaraciones globales dedicado.

4

Elimina export de dentro del bloque de ampliación

Si de verdad quieres añadir un tipo exportable nuevo a la API pública de un módulo existente, el bloque de ampliación no es el lugar adecuado. Mueve la declaración completamente fuera del bloque `declare module`. Para ampliar una interfaz existente, usa el mismo nombre de interfaz sin `export` dentro del bloque: TypeScript la fusiona automáticamente mediante la fusión de declaraciones.

Formateador y validador JSON

Valida tu tsconfig.json y package.json en busca de errores de sintaxis al instante en tu navegador, sin necesidad del compilador de TypeScript.

Open tool

TS1384 e isolatedModules

La opción del compilador `isolatedModules` está activada por defecto en Vite, Next.js, Create React App con Babel y cualquier proyecto que use esbuild o SWC. Exige que cada archivo sea transformable de forma independiente sin información de tipos entre archivos, lo que añade restricciones que amplifican varios errores de TypeScript, incluido TS1384.

Qué restringe isolatedModules

ConstrucciónSin isolatedModulesCon isolatedModules
`const enum`✓ Permitido en cualquier sitio✗ Solo en archivos .d.ts
`export type`✓ Opcional✓ Obligatorio para reexportar solo tipos
`import type`✓ Opcional✓ Obligatorio para importar solo tipos
Declaraciones ambiente✓ En cualquier archivo .ts✓ Mejor en archivos .d.ts
Ampliación de módulo✓ En archivos .ts de módulo✓ Preferible en archivos .d.ts
Reexportación de espacios de nombres✓ Permitida✗ Restringida

La solución específica para isolatedModules

Cuando `isolatedModules` está activo y TS1384 aparece en una ampliación dentro de un archivo `.ts` normal, la solución más limpia es mover la ampliación a un archivo `.d.ts`. Los archivos de declaración nunca los transforman esbuild ni Babel: solo los lee el compilador de TypeScript. Esto elimina por completo la restricción de isolatedModules para esa ampliación.

src/types/express.d.ts
typescript
// Este patrón funciona correctamente con isolatedModules
export {};

declare module 'express' {
  interface Request {
    userId?: string;
    tenantId?: string;
  }
}

Tip

Si no estás seguro de si `isolatedModules` está activado en tu proyecto, busca `"isolatedModules": true` en tu tsconfig.json. También puedes revisar la configuración del empaquetador: la plantilla tsconfig por defecto de Vite lo incluye y Next.js lo activa automáticamente al usar SWC. Usa el [Visor de diferencias](/tools/data/dev-utilities/diff-viewer) para comparar tu tsconfig con una referencia conocida cuando diagnostiques problemas de TS1384 específicos de un entorno.

TS1384 en archivos .d.ts

Los archivos de declaración añaden sus propios matices a TS1384. Las reglas sobre qué es válido en un archivo `.d.ts` difieren ligeramente de las de los archivos `.ts` normales, y los patrones que producen TS1384 en archivos de declaración suelen ser menos intuitivos.

Definición de módulo ambiente frente a ampliación

Un archivo `.d.ts` puede contener dos cosas fundamentalmente distintas que se parecen pero se comportan de forma diferente. Una definición de módulo ambiente (`declare module 'nombre' {}` en un `.d.ts` con contexto de script, sin importaciones ni exportaciones) define desde cero todos los tipos de un módulo: se usa para tipar librerías JavaScript sin tipos. Una ampliación de módulo (`declare module 'nombre' {}` en un `.d.ts` con contexto de módulo y un `export {}`) extiende los tipos de un módulo existente. La distinción importa porque `export` es válido dentro de una definición de módulo ambiente, pero produce TS1384 dentro de una ampliación de módulo.

Elegir el patrón .d.ts correcto

Si tu archivo `.d.ts` define tipos para una librería sin tipar (por ejemplo, tipar un plugin antiguo de jQuery), mantenlo como archivo de contexto de script sin `export {}` al principio. Usa `export` libremente dentro del bloque `declare module`. Si tu archivo `.d.ts` amplía una librería ya tipada (por ejemplo, añadir una propiedad a `Express.Request`), añade `export {}` al principio y elimina cualquier `export` de dentro del bloque `declare module`.

Note

Una forma rápida de determinar qué patrón aplica: si el módulo que pretendes ampliar ya tiene definiciones de tipo (mediante `@types/...` o integradas), estás ampliando. Si no tiene ningún tipo y los estás creando desde cero, estás escribiendo una definición de módulo ambiente.

skipLibCheck como último recurso

Cuando TS1384 aparece en una ruta dentro de `node_modules` y no tienes control sobre el paquete, añade `"skipLibCheck": true` a tu tsconfig.json. Esto le dice a TypeScript que omita la comprobación de tipos de todos los archivos `.d.ts`, incluidos los de `node_modules`. Es una opción de configuración legítima y muy usada, no un truco. La contrapartida es que pierdes por completo la comprobación de tipos de los archivos de declaración de las librerías, así que los tipos realmente rotos en las dependencias no se reportarán. Usa `skipLibCheck` solo cuando la alternativa sea bloquear tu compilación.

TS1384 en frameworks y empaquetadores

Cada framework y herramienta de compilación configura TypeScript de forma distinta, lo que significa que TS1384 puede aparecer por razones ligeramente diferentes según tu stack. Así es como los entornos más habituales producen y resuelven el error.

Next.js

Next.js activa `isolatedModules` automáticamente mediante su tsconfig por defecto y usa SWC para la transformación. El patrón estándar para ampliar tipos en Next.js es un directorio `types/` dedicado en la raíz del proyecto con archivos `.d.ts` que empiezan por `export {}`. Next.js también genera un archivo `next-env.d.ts`: nunca lo edites a mano, porque se regenera en cada compilación y perderás los cambios. Añade tus ampliaciones en un archivo aparte.

Vite

Los proyectos de Vite usan esbuild para la transformación e incluyen `isolatedModules: true` en el tsconfig por defecto. Vite también genera un archivo `vite-env.d.ts` para sus propios globales. Añade las ampliaciones de módulo en un directorio `src/types/` aparte. El patrón `export {}` resuelve TS1384 en todas las configuraciones estándar de Vite, y mantener las ampliaciones en archivos `.d.ts` es el enfoque más seguro cuando la transformación con esbuild está en la cadena.

APIs de Node.js / Express sin framework

Los proyectos con Express suelen ampliar `Express.Request` para añadir el contexto de sesión o autenticación del usuario. El patrón canónico es un archivo `src/types/express/index.d.ts` con `export {}` al principio seguido de la ampliación `declare module 'express-serve-static-core'`. Sin `isolatedModules`, también funciona como archivo `.ts` normal, pero usar `.d.ts` es la convención más limpia en cualquier caso. Verifica siempre el nombre exacto del módulo revisando las definiciones de tipo de Express, ya que el destino de la ampliación es `express-serve-static-core`, no `express`.

El archivo debe ser un módulo antes de poder ampliar uno. Un solo `export {}` convierte un script en módulo, y desbloquea todo el sistema de ampliación.

- Principio de ampliación de módulos de TypeScript

Evitar TS1384 a largo plazo

TS1384 es fácil de introducir sin querer, sobre todo cuando nuevos miembros del equipo añaden ampliaciones de tipo o cuando migras un proyecto a un empaquetador nuevo. Estas prácticas evitan que vuelva después de haberlo arreglado.

Establece una convención de directorio de tipos

Crea un directorio `src/types/` (o `types/`) y guarda ahí todas las ampliaciones de módulo como archivos `.d.ts`. Cada archivo debería contener una ampliación y empezar por `export {}`. Documenta esta convención en el `CONTRIBUTING.md` de tu proyecto para que los nuevos colaboradores sepan dónde van las declaraciones de tipo. Una ubicación consistente también facilita auditar las ampliaciones al actualizar dependencias.

Usa tsc --noEmit en CI

Ejecutar `tsc --noEmit` como paso de CI detecta TS1384 (y cualquier otro error de TypeScript) antes de que el código llegue a main. Muchos proyectos omiten la comprobación de tipos en CI porque su empaquetador no la necesita: esbuild y SWC eliminan los tipos sin comprobarlos. Añade `tsc --noEmit` como paso independiente del trabajo para que los errores de tipo, incluido TS1384, se detecten en cada pull request.

Usa el Visor de diferencias para auditar cambios en tsconfig

Los cambios en tsconfig.json (añadir `isolatedModules`, cambiar `moduleResolution` o actualizar `lib`) pueden introducir TS1384 en archivos que antes compilaban sin errores. Cuando llegue un cambio de tsconfig, usa el Visor de diferencias para comparar la configuración antigua y la nueva en paralelo. Así ves de inmediato qué opciones cambiaron y puedes rastrear los nuevos errores TS1384 hasta el ajuste concreto que los causó.

Tip

Después de arreglar TS1384, valida la sintaxis de tu tsconfig.json con el [Formateador y Validador JSON](/tools/data/formatters/json-formatter-viewer): los archivos tsconfig son JSON, y una coma final o una comilla que falte impedirá silenciosamente que TypeScript lea el cambio de configuración que acabas de hacer.

Visor de diferencias

Compara dos versiones de tsconfig.json, package.json o cualquier archivo de texto en paralelo para ver exactamente qué cambió, desde el navegador y sin subir nada.

Open tool

Key takeaways

  • TS1384 aparece cuando un modificador `export` figura dentro de un bloque de ampliación `declare module` o `declare global`; el arreglo casi siempre es una sola línea.
  • La causa más común: el archivo no tiene importaciones ni exportaciones, así que TypeScript lo trata como un script. Añade `export {}` al principio para convertirlo en módulo.
  • Con `isolatedModules: true` (proyectos Vite, Next.js, esbuild), mueve las ampliaciones a archivos `.d.ts`: quedan excluidos de la transformación y evitan la restricción por completo.
  • Si TS1384 señala una ruta dentro de `node_modules`, la solución es `skipLibCheck: true` en tsconfig.json: no puedes editar los archivos de declaración de las dependencias.
  • Las definiciones de módulo ambiente (tipar librerías sin tipos) y las ampliaciones de módulo (extender librerías tipadas) se parecen pero se comportan distinto: `export` dentro del bloque solo es válido en las definiciones, no en las ampliaciones.
  • Añade `tsc --noEmit` a tu pipeline de CI para detectar TS1384 en cada pull request, aunque tu empaquetador (esbuild, SWC) no haga comprobación de tipos durante la compilación.
  • Valida la sintaxis de tsconfig.json con el Formateador y Validador JSON después de los cambios: un error de sintaxis JSON impide silenciosamente que TypeScript lea tu configuración.

Preguntas frecuentes

TS1384 significa que TypeScript encontró un modificador `export` en un lugar donde no está permitido, concretamente dentro de un bloque de ampliación de módulo. El mensaje completo es: «el modificador "export" no se puede aplicar a una ampliación de módulo». Las ampliaciones de módulo extienden tipos existentes mediante `declare module '...' {}` o `declare global {}`. No pueden exportar símbolos nuevos: solo añaden declaraciones a un módulo que ya existe. Cualquier `export` dentro del bloque de ampliación provoca TS1384.

La solución más habitual es asegurarse de que el archivo sea un módulo y no un script. Añade `export {}` al principio si el archivo no tiene otras importaciones ni exportaciones. Esto lo convierte de contexto de script a contexto de módulo, algo que TypeScript exige para la sintaxis de ampliación `declare module` y `declare global`. Si lo que quieres es añadir tipos nuevos en lugar de ampliar los existentes, mueve las declaraciones de tipo fuera del bloque `declare module`.

El bloque `declare global {}` debe estar dentro de un archivo que TypeScript ya trate como módulo, es decir, con al menos un `import` o `export` de nivel superior. Sin ellos, TypeScript trata el archivo como un script, y `declare global` en un archivo de script produce TS1384. Añade `export {}` al final del archivo para forzar el modo módulo sin exportar realmente nada. Este es el patrón estándar para los archivos de ampliación de tipos globales.

Un archivo TypeScript es un script si no tiene sentencias `import` ni `export` de nivel superior: las declaraciones de los scripts comparten un ámbito global visible para todos los demás archivos de script. Un archivo con al menos un `import` o `export` es un módulo con su propio ámbito aislado. La sintaxis de ampliación de módulo solo se permite en archivos de módulo. Añadir `export {}`, una exportación vacía, convierte un script en módulo y resuelve TS1384 sin cambiar el comportamiento en tiempo de ejecución.

Sí, en escenarios concretos. Con `isolatedModules: true` en tsconfig.json, TypeScript exige que cada archivo se pueda transformar de forma independiente. Las ampliaciones solo de tipos en archivos .ts normales pueden provocar TS1384 cuando esbuild o Babel intentan procesarlas, porque esas herramientas no pueden resolver información de tipos entre archivos. Mover la ampliación a un archivo .d.ts lo resuelve: los archivos de declaración quedan excluidos de la transformación en todos los empaquetadores importantes.

Sí. Si un paquete distribuye declaraciones de tipo incorrectas que usan `export` dentro de un bloque de ampliación de módulo, tu proyecto emite TS1384 cuando TypeScript lee esas declaraciones. La solución pragmática es añadir `skipLibCheck: true` a tu tsconfig.json, lo que omite la comprobación de tipos de los archivos de declaración en node_modules. Es un apaño: la solución correcta es que el autor del paquete arregle las declaraciones. Considera abrir una incidencia en el repositorio del paquete con el contexto concreto de TS1384.

TS2669 («las ampliaciones del ámbito global solo pueden anidarse directamente en módulos externos o declaraciones de módulo ambiente») está muy relacionada. Ambos errores aparecen cuando el contexto del archivo no es el adecuado para una ampliación de módulo. TS1384 surge cuando un modificador `export` aparece dentro del propio bloque de ampliación; TS2669 surge cuando un bloque `declare global {}` está en un archivo de script en lugar de en un módulo. La solución es idéntica en ambos casos: añade al menos una sentencia `import` o `export` al archivo.

Ejecuta `tsc --noEmit` desde la raíz del proyecto: TypeScript valida el tsconfig.json e informa de los errores de configuración sin generar archivos de salida. Para errores de sintaxis JSON en el propio tsconfig.json (comas que faltan, comas finales, nombres de propiedad incorrectos), pega el contenido del archivo en el Formateador y Validador JSON de Aback Tools, que resalta los problemas de sintaxis al instante en tu navegador sin necesidad de tener instalado el compilador de TypeScript.

ShareXLinkedIn