TypeScript: O sistema de módulos do TypeScript

Última atualização: 2026-08-26

Os módulos são as unidades básicas para organizar o código — o TypeScript oferece suporte a módulos ES e módulos CommonJS, além de permitir a exportação de tipos.

1. Noções básicas sobre módulos ES

(1) Exportação de nomes

TYPESCRIPT
// utils.ts —— Name Export
export function add(a: number, b: number): number {
  return a + b;
}

export function multiply(a: number, b: number): number {
  return a * b;
}

export const PI = 3.14159;
TYPESCRIPT
// main.ts —— Import by Name
import { add, multiply, PI } from "./utils";

console.log(add(1, 2));        // 3
console.log(multiply(3, 4));   // 12
console.log(PI);               // 3.14159

(2) Exportação padrão

TYPESCRIPT
// logger.ts —— Default Export
export default class Logger {
  constructor(private prefix: string) {}

  log(message: string): void {
    console.log(`[${this.prefix}] ${message}`);
  }
}
TYPESCRIPT
// main.ts —— Default Import(No curly braces needed,Custom Name)
import Logger from "./logger";
// That's fine, too.:import MyLogger from "./logger";

let logger = new Logger("APP");
logger.log("App Launch");  // [APP] App Launch

(3) Utilizando tanto as exportações padrão quanto as exportações nomeadas

TYPESCRIPT
// api.ts
export default class ApiClient {
  constructor(private baseUrl: string) {}

  async get(path: string): Promise<any> {
    // ...
  }
}

export enum HttpMethod {
  GET = "GET",
  POST = "POST",
  PUT = "PUT",
  DELETE = "DELETE"
}
TYPESCRIPT
// main.ts
import ApiClient, { HttpMethod } from "./api";

let client = new ApiClient("https://api.example.com");
let method: HttpMethod = HttpMethod.GET;

▶ Exemplo: Uma calculadora modular

TYPESCRIPT
// calculator/operations.ts
export function add(a: number, b: number): number { return a + b; }
export function subtract(a: number, b: number): number { return a - b; }
export function multiply(a: number, b: number): number { return a * b; }
export function divide(a: number, b: number): number {
  if (b === 0) throw new Error("The divisor cannot be zero.");
  return a / b;
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
// Executed successfully
TYPESCRIPT
// calculator/index.ts
export { add, subtract, multiply, divide } from "./operations";
export type { Operation } from "./types";

// Default Export——Calculator Category
import * as ops from "./operations";

export default class Calculator {
  compute(op: string, a: number, b: number): number {
    switch (op) {
      case "+": return ops.add(a, b);
      case "-": return ops.subtract(a, b);
      case "*": return ops.multiply(a, b);
      case "/": return ops.divide(a, b);
      default: throw new Error(`Unknown Operation:${op}`);
    }
  }
}


2. Exportação de tipos

O TypeScript permite exportar tipos individualmente — um recurso que não está presente no sistema de módulos do JavaScript:

(1) O modificador type

TYPESCRIPT
// types.ts
export interface User {
  id: number;
  name: string;
  email: string;
}

export type UserId = number;

export type UserRole = "admin" | "editor" | "viewer";

// Use export type to explicitly mark"Export Types Only"
export type { User as UserType };

(2) Distinguir entre tipos e valores ao importar

TYPESCRIPT
// main.ts
import { type User, type UserRole, createUser } from "./types";
//        ↑ type Modifier Notation"Import Types Only"——It will be erased after compilation.

// Equivalent Old Syntax
// import { User, UserRole } from "./types";  // May result in runtime imports

// Recommended New Syntax——Clearly Distinguish Between Type Import and Value Import
import type { User, UserRole } from "./types";
import { createUser } from "./types";
💡 Por que fazer essa distinção? import type Os tipos importados são completamente removidos após a compilação — eles não resultam em chamadas em tempo de execução para require ou import. Isso é fundamental para cenários que utilizam apenas tipos (como anotações de tipo e interfaces), pois evita o carregamento desnecessário de módulos.

(3) Importações de tipos inline

TYPESCRIPT
// Mixed Import——Values and Types
import { createUser, type User, type UserRole } from "./types";

// createUser is the value——Requirements for runtime
// User and UserRole is a type——Compile-Time Erasure


3. Reexportação e arquivos de bucket

(1) Reexportação

TYPESCRIPT
// Re-exporting members of one module from another module
export { User, UserId } from "./user-types";
export { Product, ProductId } from "./product-types";
export { Order, OrderId } from "./order-types";

(2) Lixa cilíndrica

index.ts Como ponto de entrada para o diretório, reexporte todas as APIs públicas:

TYPESCRIPT
// models/index.ts —— Bucket files
export { User, UserId } from "./user";
export { Product, ProductId } from "./product";
export { Order, OrderId } from "./order";
export type { CreateUser, UpdateUser } from "./user";
export type { CreateProduct, UpdateProduct } from "./product";
TYPESCRIPT
// Import directly from the directory when using it
import { User, Product, type CreateUser } from "./models";
// without needing to know which specific file it is in
💡 Prós: Simplifica os caminhos de importação, oculta a estrutura interna dos arquivos e controla a API pública. Contras: Pode importar módulos desnecessários (o tree-shaking pode não otimizar totalmente o código).



4. Estratégias de análise de módulos

O TypeScript precisa saber como resolver import "./utils" em um arquivo real — isso é determinado pela estratégia de resolução de módulos.

(1) Duas estratégias de análise sintática

Estratégia Objetivo Descrição
classic Compatibilidade com versões anteriores Pesquise primeiro por .ts e, em seguida, por .d.ts
node (Recomendado) Projeto TS moderno Simula a lógica de análise do Node.js

(2) Ordem de consulta para estratégias de análise de nós

TEXT 📖 Somente leitura
import { X } from "./utils"

Ordem de pesquisa:

  1. ./utils.ts
  2. ./utils.tsx
  3. ./utils.d.ts
  4. O campo types em ./utils/package.json
  5. ./utils/index.ts
  6. ./utils/index.d.ts

(3) Pesquisando em node_modules

TEXT 📖 Somente leitura
import _ from "lodash"

Ordem de pesquisa:

  1. ./node_modules/lodash.ts (Não existe)
  2. Campo ./node_modules/lodash/package.jsontypes/typings
  3. ./node_modules/lodash/index.d.ts
  4. ./node_modules/@types/lodash/index.d.ts
  5. Pesquise ../node_modules/../../node_modules/ ...


5. Mapeamento de caminhos (Path Mapping)

Use aliases de caminho em projetos grandes para evitar caminhos relativos longos:

(1) Configuração do tsconfig.json

JSON
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@utils/*": ["src/utils/*"],
      "@models/*": ["src/models/*"],
      "@components/*": ["src/components/*"]
    }
  }
}

(2) Uso de aliases de caminho

TYPESCRIPT
// No aliases——Relative paths are prone to errors
import { User } from "../../../models/user";
import { formatDate } from "../../utils/date";

// Has an alias——Clear and concise
import { User } from "@models/user";
import { formatDate } from "@utils/date";
⚠️ Observação: Os aliases de caminho são apenas mapeamentos em tempo de compilação — o tempo de execução (Node.js/navegador) não reconhece caminhos como @models. É necessário usar uma ferramenta de compilação (como o resolve.alias do Webpack, o resolve.alias do Vite ou o tsc-alias) para realizar a substituição de caminhos em tempo de execução.



6. Interoperabilidade com CommonJS

(1) Módulos CommonJS

TYPESCRIPT
// Use CommonJS style export
// math.cjs
const add = (a, b) => a + b;
const multiply = (a, b) => a * b;
module.exports = { add, multiply };

(2) Importando CommonJS no TS

TYPESCRIPT
// esModuleInterop: false(Default)
import * as math from "./math.cjs";
math.add(1, 2);

// esModuleInterop: true(Recommendations)
import math from "./math.cjs";   // ✅ A More Natural Way to Introduce It
math.add(1, 2);

(3) Permitir exportações CommonJS a partir do TS

TYPESCRIPT
// Use export = syntax to export CommonJS Style
class Calculator {
  add(a: number, b: number): number { return a + b; }
}
export = Calculator;

// Use the following when importing: import = require
import Calculator = require("./calculator");
let calc = new Calculator();
💡 Recomendação: Use módulos ES (import/export) em todos os novos projetos e habilite esModuleInterop: true para manter a compatibilidade com pacotes CommonJS legados. Use export = e import = apenas quando for necessária compatibilidade estrita com o CommonJS.



▶ Exemplo: Exportações nomeadas vs padrão lado a lado

TYPESCRIPT
// config.ts — named and default exports together
export const APP_NAME = "MyApp";
export const VERSION = "1.0.0";

export default class AppConfig {
  constructor(public port: number = 3000) {}
  toString(): string { return `${APP_NAME} v${VERSION} on :${this.port}`; }
}
▶ Experimente
TYPESCRIPT
// main.ts — importing both styles
import AppConfig, { APP_NAME, VERSION } from "./config";

let config = new AppConfig(8080);
console.log(config.toString());  // MyApp v1.0.0 on :8080
console.log(APP_NAME);           // MyApp

Saída:

TEXT 📖 Somente leitura
MyApp v1.0.0 on :8080
MyApp

▶ Exemplo: import type para importações apenas de tipo

TYPESCRIPT
// shapes.ts
export interface Circle { kind: "circle"; radius: number; }
export interface Square { kind: "square"; side: number; }
export type Shape = Circle | Square;

export function area(shape: Shape): number {
  return shape.kind === "circle"
    ? Math.PI * shape.radius ** 2
    : shape.side ** 2;
}
▶ Experimente
TYPESCRIPT
// main.ts — import type for types, regular import for values
import type { Circle, Square, Shape } from "./shapes";
import { area } from "./shapes";

let c: Circle = { kind: "circle", radius: 5 };
let s: Shape = { kind: "square", side: 4 };

console.log(area(c)); // 78.5398...
console.log(area(s)); // 16

Saída:

TEXT 📖 Somente leitura
78.53981633974483
16

❓ Perguntas Frequentes

P: Qual é a diferença entre import type e um import comum? R: import type Os tipos importados dessa forma são completamente apagados após a compilação e não resultam no carregamento de módulos em tempo de execução. Uma instrução import comum importa tanto valores quanto tipos e resulta em uma chamada require() após a compilação. Ao usar apenas tipos (como interfaces ou aliases de tipo), certifique-se de usar import type para evitar importações desnecessárias em tempo de execução.

P: Deve-se usar arquivos de agrupamento (index.ts)? R: Eles são recomendados para bibliotecas e APIs públicas — para simplificar as importações e controlar as interfaces exportadas. Para aplicativos internos, depende da situação — eles não são necessários para projetos pequenos, mas oferecem benefícios organizacionais para projetos grandes. A principal desvantagem é que eles podem afetar o “tree-shaking”, mas os empacotadores modernos lidam bem com isso.

P: Como os aliases de caminho entram em vigor em tempo de execução? R: O código JS gerado pelo TypeScript ainda usa caminhos de alias (como @models/user), que não são reconhecidos em tempo de execução. A substituição de caminhos deve ser feita por uma ferramenta de compilação — o Webpack usa resolve.alias, o Vite usa resolve.alias e a compilação pura com o tsc requer pós-processamento por ferramentas como tsc-alias.

P: O que devo usar, ES Modules ou CommonJS? R: Para novos projetos, use exclusivamente ES Modules (import/export). O CommonJS é o sistema de módulos legado do Node.js e está sendo descontinuado. A opção esModuleInterop no TypeScript permite que você use pacotes CommonJS sem problemas. Os navegadores e o Deno suportam apenas ES Modules.

📖 Resumo

📝 Exercícios

  1. Exercício básico (Dificuldade ⭐): Crie três arquivos de módulo — math.ts (exporta soma/subtração), string-utils.ts (exporta maiúsculas/inversão) e index.ts (reexporta o arquivo bucket). Importe-os e utilize-os no main.ts.
  2. Exercício avançado (Dificuldade ⭐⭐): Configure os mapeamentos de caminho para um projeto existente — mapeie @utils para src/utils e @models para src/models. Use import type para importar tipos e use simplesmente import para importar valores.
  3. Desafio (Dificuldade: ⭐⭐⭐): Escreva um arquivo de declaração que permita que o pacote CommonJS legacy-sdk seja importado para o TypeScript no estilo ES Module — import LegacySDK from "legacy-sdk". Considere os dois casos: quando esModuleInterop está habilitado e quando está desabilitado.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%