O erro TS1384 do TypeScript é daqueles que parecem crípticos no primeiro contato, mas que sempre têm uma causa precisa e corrigível. Ele aparece quando o compilador encontra um modificador export num local onde ele não pode estar legalmente, mais precisamente dentro de um bloco de ampliação de módulo. Este guia explica exatamente o que o TS1384 significa, percorre todos os cenários que o disparam e apresenta a correção correta para cada um.
O que é o TS1384?
O erro TS1384 do TypeScript traz a mensagem: «o modificador "export" não pode ser aplicado a uma ampliação de módulo». Ele aparece quando o compilador encontra a palavra-chave `export` dentro de um bloco `declare module` ou `declare global`, as duas construções que o TypeScript usa para ampliação de módulos. Blocos de ampliação servem para estender os tipos de módulos existentes, não para declarar símbolos públicos novos, então `export` é estruturalmente inválido dentro deles.
Ampliação de módulo em uma frase
A ampliação de módulo é o mecanismo do TypeScript que permite adicionar membros novos aos tipos de um módulo existente: por exemplo, adicionar uma propriedade personalizada a `Express.Request`, estender `Window` com um global de terceiros ou adicionar métodos às opções de componentes de um framework. A sintaxe se parece com um bloco `declare module 'nome-do-módulo' {}` e precisa ficar num arquivo de módulo (um arquivo com ao menos uma instrução `import` ou `export` de nível superior).
- TS1384 é um erro do compilador: o arquivo não passa na verificação de tipos até ser corrigido
- Não afeta o tempo de execução: o erro é puramente sobre declarações de tipo
- É determinístico: o mesmo código sempre o dispara; não existe versão intermitente
- Tem poucas causas raiz: contexto de script contra módulo, isolatedModules e estrutura .d.ts incorreta cobrem 95% dos casos
Note
Quando o TS1384 aparece
O erro sempre envolve um `export` num local onde o TypeScript não o permite. Existem três padrões distintos que o produzem, e identificar qual deles se aplica ao seu código determina a correção correta.
Padrão 1: export dentro de um bloco declare module
O gatilho mais direto: você escreve uma instrução `export` dentro de uma ampliação `declare module`. A intenção normalmente é adicionar algo à API pública do módulo, mas blocos de ampliação não funcionam assim: eles só podem estender declarações de tipo que já existem no módulo de destino.
// ✗ TS1384 - export dentro de uma ampliação de módulo
declare module 'some-library' {
export interface NewInterface { // <-- o TS1384 aparece aqui
id: string;
}
}
// ✓ Correto - interface adicionada sem export
declare module 'some-library' {
interface ExistingInterface {
newProperty: string; // estende o tipo existente
}
}Padrão 2: o arquivo é tratado como script, não como módulo
Essa é a causa mais comum do TS1384 em projetos reais. Se um arquivo não tem instruções `import` ou `export` de nível superior, o TypeScript o trata como um script de escopo global. Um bloco `declare global {}` num arquivo de script não faz sentido (os globais já são globais em scripts), então o TypeScript rejeita qualquer `export` dentro dele com o TS1384. O arquivo precisa ser um módulo para que o contexto de ampliação faça sentido.
Padrão 3: estrutura incorreta no arquivo .d.ts
Arquivos de declaração (`.d.ts`) que misturam declarações de módulo ambiente com instruções `export` comuns na ordem errada podem disparar o TS1384. Um `.d.ts` que começa com declarações `export` de nível superior e depois contém um bloco `declare module` é tratado como módulo, o que está correto. Mas um `.d.ts` que envolve tudo num único bloco `declare module` e depois tenta usar `export` dentro desse bloco confunde o contexto de ampliação com um contexto de definição de módulo.
Warning
Como corrigir o TS1384: ampliação de módulo
A correção certa depende do que você realmente quer alcançar. Existem dois objetivos diferentes que podem levar ao TS1384 e eles exigem abordagens distintas. Siga estes quatro passos para resolver o erro de forma limpa.
Identifique qual padrão está disparando o TS1384
Leia com atenção o erro completo do compilador. Repare na extensão do arquivo (.ts ou .d.ts), no número da linha e se o `export` está dentro de um bloco `declare module`, de um bloco `declare global` ou em outro lugar. O contexto do código ao redor mostra qual dos três padrões acima se aplica. Se o caminho do erro começar com `node_modules/`, pule para a correção com `skipLibCheck`: os outros padrões não se aplicam.
Adicione export {} para converter o arquivo em módulo
Se o seu arquivo tem um bloco `declare module` ou `declare global` mas não tem imports ou exports de nível superior, adicione `export {}` no topo. Essa única linha converte o arquivo de contexto de script para contexto de módulo, o ambiente exigido pela sintaxe de ampliação. O export vazio não adiciona nada ao resultado compilado: é puramente um sinal de contexto para o TypeScript.
// Adicione esta linha para converter o arquivo em módulo
export {};
declare global {
interface Window {
myAnalytics: AnalyticsInstance;
}
}Mova o declare global para um módulo existente
Uma alternativa a adicionar `export {}` é colocar o bloco `declare global` dentro de um arquivo que já tenha imports ou exports reais, como o ponto de entrada de uma biblioteca, um módulo de funcionalidade ou um arquivo de utilitários compartilhados. Essa abordagem mantém as suas ampliações de tipo junto do código que elas estendem, o que pode ser mais fácil de manter do que um arquivo de declarações globais dedicado.
Remova o export de dentro do bloco de ampliação
Se você realmente quer adicionar um tipo exportável novo à API pública de um módulo existente, o bloco de ampliação não é o lugar certo. Mova a declaração totalmente para fora do bloco `declare module`. Para ampliar uma interface existente, use o mesmo nome de interface sem `export` dentro do bloco: o TypeScript faz a fusão automaticamente pela fusão de declarações.
Formatador e validador JSON
Valide seu tsconfig.json e package.json em busca de erros de sintaxe na hora no navegador, sem precisar do compilador TypeScript.
TS1384 e isolatedModules
A opção de compilador `isolatedModules` vem ativada por padrão no Vite, Next.js, Create React App com Babel e em qualquer projeto que use esbuild ou SWC. Ela exige que cada arquivo possa ser transformado de forma independente, sem informação de tipos entre arquivos, o que acrescenta restrições que amplificam vários erros do TypeScript, incluindo o TS1384.
O que o isolatedModules restringe
| Construção | Sem isolatedModules | Com isolatedModules |
|---|---|---|
| `const enum` | ✓ Permitido em qualquer lugar | ✗ Apenas em arquivos .d.ts |
| `export type` | ✓ Opcional | ✓ Obrigatório para reexportar só tipos |
| `import type` | ✓ Opcional | ✓ Obrigatório para importar só tipos |
| Declarações ambiente | ✓ Em qualquer arquivo .ts | ✓ Melhor em arquivos .d.ts |
| Ampliação de módulo | ✓ Em arquivos .ts de módulo | ✓ Preferível em arquivos .d.ts |
| Reexportação de namespaces | ✓ Permitida | ✗ Restrita |
A correção específica para isolatedModules
Quando o `isolatedModules` está ativo e o TS1384 aparece numa ampliação dentro de um arquivo `.ts` comum, a correção mais limpa é mover a ampliação para um arquivo `.d.ts`. Arquivos de declaração nunca são transformados pelo esbuild ou pelo Babel: apenas o compilador TypeScript os lê. Isso elimina totalmente a restrição do isolatedModules para essa ampliação.
// Este padrão funciona corretamente com isolatedModules
export {};
declare module 'express' {
interface Request {
userId?: string;
tenantId?: string;
}
}Tip
TS1384 em arquivos .d.ts
Arquivos de declaração trazem nuances próprias ao TS1384. As regras sobre o que é válido num arquivo `.d.ts` diferem um pouco das de arquivos `.ts` comuns, e os padrões que produzem o TS1384 em arquivos de declaração costumam ser menos intuitivos.
Definição de módulo ambiente ou ampliação?
Um arquivo `.d.ts` pode conter duas coisas fundamentalmente diferentes que se parecem, mas se comportam de modo distinto. Uma definição de módulo ambiente (`declare module 'nome' {}` num `.d.ts` em contexto de script, sem imports ou exports) define do zero todos os tipos de um módulo: ela é usada para tipar bibliotecas JavaScript sem tipos. Uma ampliação de módulo (`declare module 'nome' {}` num `.d.ts` em contexto de módulo com um `export {}`) estende os tipos de um módulo existente. A distinção importa porque `export` é válido numa definição de módulo ambiente, mas produz TS1384 numa ampliação de módulo.
Escolher o padrão .d.ts correto
Se o seu arquivo `.d.ts` define tipos para uma biblioteca sem tipagem (por exemplo, tipar um plugin antigo de jQuery), mantenha-o como arquivo de contexto de script sem `export {}` no topo. Use `export` livremente dentro do bloco `declare module`. Se o seu arquivo `.d.ts` amplia uma biblioteca já tipada (por exemplo, adicionar uma propriedade a `Express.Request`), adicione `export {}` no topo e remova qualquer `export` de dentro do bloco `declare module`.
Note
skipLibCheck como último recurso
Quando o TS1384 aparece num caminho dentro de `node_modules` e você não tem controle sobre o pacote, adicione `"skipLibCheck": true` ao tsconfig.json. Isso diz ao TypeScript para ignorar a verificação de tipos de todos os arquivos `.d.ts`, inclusive os de `node_modules`. É uma opção de configuração legítima e muito usada, não um truque. O custo é perder totalmente a verificação de tipos das declarações das bibliotecas, então tipos de fato quebrados em dependências não serão reportados. Use `skipLibCheck` só quando a alternativa for travar o seu build.
TS1384 em frameworks e bundlers
Cada framework e ferramenta de build configura o TypeScript de um jeito, o que significa que o TS1384 pode aparecer por motivos um pouco diferentes conforme a sua stack. Veja como os ambientes mais comuns produzem e resolvem o erro.
Next.js
O Next.js ativa o `isolatedModules` automaticamente pelo tsconfig padrão e usa SWC para a transformação. O padrão usual para ampliar tipos no Next.js é um diretório `types/` dedicado na raiz do projeto com arquivos `.d.ts` começando por `export {}`. O Next.js também gera um arquivo `next-env.d.ts`: nunca o edite à mão, pois ele é regenerado a cada build e suas mudanças serão perdidas. Coloque suas ampliações num arquivo separado.
Vite
Projetos Vite usam esbuild para a transformação e incluem `isolatedModules: true` no tsconfig padrão. O Vite também gera um arquivo `vite-env.d.ts` para os seus próprios globais. Adicione ampliações de módulo num diretório `src/types/` separado. O padrão `export {}` resolve o TS1384 em todas as configurações Vite padrão, e manter as ampliações em arquivos `.d.ts` é a abordagem mais segura quando a transformação com esbuild está na cadeia.
APIs Node.js / Express simples
Projetos com Express costumam ampliar `Express.Request` para adicionar sessão de usuário ou contexto de autenticação. O padrão canônico é um arquivo `src/types/express/index.d.ts` com `export {}` no topo seguido da ampliação `declare module 'express-serve-static-core'`. Sem `isolatedModules`, isso também funciona num arquivo `.ts` comum, mas usar `.d.ts` é a convenção mais limpa em qualquer caso. Verifique sempre o nome exato do módulo nas definições de tipo do Express, porque o alvo da ampliação é `express-serve-static-core`, não `express`.
O arquivo precisa ser um módulo antes de poder ampliar um. Um único `export {}` transforma um script em módulo e destrava todo o sistema de ampliação.
Evitar o TS1384 a longo prazo
O TS1384 entra em cena facilmente por acidente, principalmente quando membros novos da equipe adicionam ampliações de tipo ou quando você migra um projeto para um bundler novo. Estas práticas impedem que ele volte depois de corrigido.
Estabeleça uma convenção de diretório de tipos
Crie um diretório `src/types/` (ou `types/`) e mantenha lá todas as ampliações de módulo como arquivos `.d.ts`. Cada arquivo deve conter uma ampliação e começar por `export {}`. Documente essa convenção no `CONTRIBUTING.md` do projeto para que novos contribuidores saibam onde as declarações de tipo devem ficar. Uma localização consistente também facilita auditar ampliações ao atualizar dependências.
Use tsc --noEmit no CI
Rodar `tsc --noEmit` como etapa de CI detecta o TS1384 (e qualquer outro erro do TypeScript) antes de o código chegar à main. Muitos projetos pulam a verificação de tipos no CI porque o bundler não a exige: esbuild e SWC removem os tipos sem verificá-los. Adicione `tsc --noEmit` como etapa separada do job para que erros de tipo, incluindo o TS1384, sejam pegos em cada pull request.
Use o visualizador de diferenças para auditar mudanças no tsconfig
Mudanças no tsconfig.json, como adicionar `isolatedModules`, trocar `moduleResolution` ou atualizar `lib`, podem introduzir TS1384 em arquivos que antes compilavam limpos. Quando uma mudança de tsconfig chega, use o Visualizador de diferenças para comparar a configuração antiga e a nova lado a lado. Assim fica imediatamente visível quais opções mudaram e você consegue rastrear os novos erros de TS1384 até a configuração específica que os causou.
Tip
Visualizador de diferenças
Compare duas versões de tsconfig.json, package.json ou qualquer arquivo de texto lado a lado para ver exatamente o que mudou, no navegador e sem enviar nada.
Key takeaways
- O TS1384 aparece quando um modificador `export` está dentro de um bloco de ampliação `declare module` ou `declare global`; a correção quase sempre cabe em uma linha.
- A causa mais comum: o arquivo não tem imports nem exports, então o TypeScript o trata como script. Adicione `export {}` no topo para convertê-lo em módulo.
- Com `isolatedModules: true` (projetos Vite, Next.js, esbuild), mova as ampliações para arquivos `.d.ts`: eles ficam fora da transformação e evitam a restrição por completo.
- Se o TS1384 aponta para um caminho dentro de `node_modules`, a correção é `skipLibCheck: true` no tsconfig.json: você não pode editar as declarações de uma dependência.
- Definições de módulo ambiente (tipar bibliotecas sem tipos) e ampliações de módulo (estender bibliotecas tipadas) se parecem, mas se comportam diferente: `export` dentro do bloco só é válido nas definições, não nas ampliações.
- Adicione `tsc --noEmit` ao seu pipeline de CI para pegar o TS1384 em cada pull request, mesmo que o seu bundler (esbuild, SWC) não faça verificação de tipos durante o build.
- Valide a sintaxe do tsconfig.json com o Formatador e validador JSON após mudanças: um erro de sintaxe JSON impede silenciosamente o TypeScript de ler a sua configuração.