Módulos e namespaces
1. Fundamentos de Módulos no TypeScript
Módulos no TypeScript representam a forma moderna de organizar e compartilhar código entre arquivos. Diferentemente de scripts tradicionais, módulos possuem seu próprio escopo, evitando poluição do escopo global e permitindo controle explícito sobre o que é exposto ou consumido externamente.
O TypeScript segue o sistema de módulos ES (ECMAScript Modules) como padrão, mas também oferece suporte a outros formatos como CommonJS, AMD e UMD, configuráveis via tsconfig.json. A sintaxe fundamental utiliza export para expor membros e import para consumi-los:
// utils/matematica.ts
export function somar(a: number, b: number): number {
return a + b;
}
export const PI = 3.14159;
// app.ts
import { somar, PI } from './utils/matematica';
console.log(somar(5, 3)); // 8
Reexportações permitem consolidar múltiplos módulos em um ponto central:
// utils/index.ts
export { somar, PI } from './matematica';
export { formatarData } from './datas';
Módulos internos vs. externos: Historicamente, o TypeScript chamava namespaces de "módulos internos" e arquivos com import/export de "módulos externos". Hoje, a terminologia evoluiu: módulos referem-se exclusivamente a arquivos com importações/exportações, enquanto namespaces são uma construção separada.
2. Módulos ES: Sintaxe Avançada
Exportações nomeadas vs. exportação default:
// exportação nomeada (múltiplas por módulo)
export function validarEmail(email: string): boolean { ... }
export class Usuario { ... }
// exportação default (uma por módulo)
export default class Configuracao { ... }
Importações com alias e namespace:
// alias para evitar conflitos
import { Usuario as User } from './models';
import { default as Config } from './config';
// importação de namespace (agrupa todas exportações)
import * as Utilitarios from './utils';
Utilitarios.somar(2, 3);
Dynamic imports com suporte a tipos:
async function carregarModuloPesado() {
const modulo = await import('./modulo-pesado');
const resultado = modulo.executar();
return resultado;
}
O TypeScript preserva a tipagem mesmo em imports dinâmicos, retornando uma Promise do tipo do módulo importado.
3. Namespaces: Organização Interna de Código
Namespaces são uma forma de agrupar código relacionado dentro de um escopo nomeado, evitando conflitos globais. Eram a principal forma de organização antes dos módulos ES se tornarem padrão.
namespace Validacao {
export function email(valor: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(valor);
}
export function cpf(valor: string): boolean {
return valor.length === 11;
}
namespace Interno {
export function sanitizar(texto: string): string {
return texto.trim().toLowerCase();
}
}
}
// Uso com nome qualificado
Validacao.email('teste@exemplo.com'); // true
Validacao.Interno.sanitizar(' TESTE '); // 'teste'
Namespaces podem ser divididos em múltiplos arquivos usando /// <reference>:
// validacao.ts
namespace Validacao {
export function email(valor: string): boolean { ... }
}
// validacao-cpf.ts
/// <reference path="validacao.ts" />
namespace Validacao {
export function cpf(valor: string): boolean { ... }
}
4. Módulos vs. Namespaces: Quando Usar Cada Um
Vantagens dos módulos:
- Isolamento completo de escopo
- Suporte nativo a tree-shaking (eliminação de código morto)
- Interoperabilidade com ecossistema JavaScript moderno
- Carregamento assíncrono via dynamic imports
- Melhor integração com bundlers (Webpack, Rollup, Vite)
Casos de uso para namespaces:
- Scripts legados que não utilizam sistema de módulos
- Declarações de tipos globais em arquivos .d.ts
- Ambientes sem suporte a ES Modules (ex: scripts no navegador sem bundler)
Boas práticas: Em projetos modernos, prefira módulos. Namespaces são considerados obsoletos para novos desenvolvimentos, exceto em cenários específicos de declaração de tipos.
5. Módulos no Sistema de Módulos do TypeScript
O tsconfig.json oferece configurações cruciais para o comportamento de módulos:
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "node",
"baseUrl": "./src",
"paths": {
"@models/*": ["models/*"],
"@utils/*": ["utils/*"]
}
}
}
Opções de module:
- ESNext/ES2020 — para projetos modernos com bundlers
- CommonJS — para Node.js tradicional
- AMD — para carregamento assíncrono no navegador
- UMD — para bibliotecas que funcionam em múltiplos ambientes
Path mapping permite criar aliases elegantes:
// Em vez de: import { Usuario } from '../../models/usuario'
import { Usuario } from '@models/usuario';
6. Namespaces e Declarações de Tipos (Ambient Modules)
Para descrever bibliotecas JavaScript sem tipos, usamos declarações ambientes:
// types/minha-biblioteca.d.ts
declare module 'minha-biblioteca' {
export function fazerAlgo(param: string): number;
export class Cliente {
constructor(nome: string);
getNome(): string;
}
}
Namespaces em arquivos .d.ts são comuns para bibliotecas globais:
// types/jquery.d.ts
declare namespace $ {
function ajax(config: object): void;
function (seletor: string): JQueryElement;
interface JQueryElement {
hide(): void;
show(): void;
}
}
7. Interoperabilidade entre Módulos e Namespaces
É possível exportar namespaces a partir de módulos:
// formas.ts
export namespace Formas {
export class Circulo {
constructor(public raio: number) {}
area(): number {
return Math.PI * this.raio ** 2;
}
}
}
// app.ts
import { Formas } from './formas';
const circulo = new Formas.Circulo(5);
Para migração gradual de namespaces para módulos, mantenha ambos funcionando durante a transição:
// antigo: namespace MeuApp { ... }
// novo:
export namespace MeuApp {
export function funcaoAntiga() { ... }
}
// arquivo novo
export function funcaoNova() { ... }
Conclusão
Módulos são o padrão moderno para organização de código em TypeScript, oferecendo isolamento, interoperabilidade e suporte a técnicas avançadas como lazy loading. Namespaces ainda têm seu lugar em cenários específicos, especialmente em declarações de tipos e código legado, mas devem ser evitados em projetos novos. A escolha entre um e outro depende do contexto, mas a tendência clara é a adoção de módulos ES como padrão universal.
Referências
- TypeScript: Modules — Documentação oficial sobre módulos no TypeScript, cobrindo sintaxe básica e avançada
- TypeScript: Namespaces — Guia completo sobre namespaces, incluindo aninhamento e distribuição em múltiplos arquivos
- TypeScript: Module Resolution — Explicação detalhada sobre como o TypeScript resolve módulos, com estratégias classic e node
- TypeScript: tsconfig.json - module — Referência completa das opções de configuração do sistema de módulos no tsconfig.json
- TypeScript Deep Dive: Modules — Tutorial aprofundado sobre módulos no TypeScript, com exemplos práticos de importação, exportação e configuração
- Migrating from Namespaces to Modules — Guia oficial de migração de namespaces para módulos ES, com estratégias de transição gradual