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.
¿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
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.
// ✗ 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
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.
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.
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.
// Añade esta línea para convertir el archivo en módulo
export {};
declare global {
interface Window {
myAnalytics: AnalyticsInstance;
}
}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.
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.
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ón | Sin isolatedModules | Con 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.
// Este patrón funciona correctamente con isolatedModules
export {};
declare module 'express' {
interface Request {
userId?: string;
tenantId?: string;
}
}Tip
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
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.
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
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.
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.