esModuleInterop no tsconfig: Guia completo para TypeScript

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Por que esModuleInterop não é apenas uma opção no tsconfig

\n\n

Se você já escreveu em TypeScript e importou uma biblioteca como express ou lodash, certamente já se deparou com o momento em que o compilador reclama de import * as express from 'express'. Ou, ao contrário, você usa tranquilamente import express from 'express', mas no código JavaScript gerado vê uma construção estranha module.exports.default. Que mágica é essa? A mágica (ou a falta dela) é a flag esModuleInterop no seu tsconfig.json.

\n\n

Este parâmetro é uma das perguntas mais populares no Stack Overflow (milhares de visualizações!), e não é surpresa: sem entendê-lo, é fácil cair na armadilha da incompatibilidade de módulos. Neste tutorial, não vamos apenas explicar a teoria, mas percorrer o caminho do problema à solução com exemplos práticos. Vamos lá!

\n\n

O problema: Conflito de dois mundos de módulos

\n\n

TypeScript é uma extensão do JavaScript, e o JavaScript historicamente tem dois sistemas principais de módulos:

\n
    \n
  • CommonJS (CJS) — padrão do Node.js, usa require() e module.exports. Exemplo: const express = require('express');
  • \n
  • ES Modules (ESM) — padrão moderno, usa import e export. Exemplo: import express from 'express';
  • \n
\n

O problema é que esses sistemas tratam a exportação padrão (default export) de maneiras diferentes. No ESM, um módulo pode ter um export default, e ele é importado como import name from 'module'. No CommonJS, não existe o conceito de "exportação padrão" — existe apenas o objeto module.exports, que pode ser qualquer coisa.

\n\n

Quando o TypeScript compila seu código para CommonJS (o que é frequentemente necessário para Node.js), ele precisa decidir: como representar import x from 'y' na forma de require()? Sem o esModuleInterop, o TypeScript faz isso literalmente: cria module.exports.default, o que quebra a importação de bibliotecas escritas para CommonJS.

\n\n

O que é esModuleInterop?

\n\n

esModuleInterop é uma flag no tsconfig.json que ativa compatibilidade adicional entre CommonJS e ES Modules. Quando definida como true, o TypeScript gera código auxiliar que permite escrever import foo from 'bar' mesmo para módulos CommonJS que não possuem um default-export.

\n\n

Por padrão, no TypeScript 4.x e superiores, essa flag é true (se você usar --init), mas em projetos antigos ela era frequentemente desativada. Por quê? Porque ela altera o comportamento da importação e, sem entendê-la, isso leva a bugs.

\n\n

Como fica no tsconfig.json

\n
{\n  "compilerOptions": {\n    "esModuleInterop": true,\n    // outras configurações...\n  }\n}\n
\n\n

Ativar esta flag também ativa automaticamente o allowSyntheticDefaultImports, que permite a importação padrão de módulos sem um default-export real no nível de tipos.

\n\n

Tutorial passo a passo: do problema à solução

\n\n

Vamos analisar a situação com um exemplo real. Suponha que temos uma biblioteca simples em CommonJS:

\n\n
// myLib.js (CommonJS)\nmodule.exports = function greet(name) {\n  return `Olá, ${name}!`;\n};\n
\n\n

Queremos usá-la em um projeto TypeScript. Vamos criar o arquivo index.ts:

\n\n
// index.ts\nimport greet from './myLib';\nconsole.log(greet('Mundo'));\n
\n\n

Agora, vejamos o que acontece ao compilar com diferentes configurações de esModuleInterop.

\n\n

Passo 1: Sem esModuleInterop (false)

\n\n

Vamos executar a compilação com "esModuleInterop": false. O TypeScript emitirá um erro:

\n
O módulo '"myLib"' não tem d                

Blogs

Book Recommendations