Kaique Mitsuo Silva Yamamoto
Arquitetura softwareFrontend webTypeScript

Performance em TypeScript

Otimização de compilação, bundle size, tree shaking, type-only imports e o TypeScript nativo em Go (10x mais rápido).

Performance em TypeScript

Performance em TypeScript opera em três camadas: compilação (velocidade do tsc), bundle (tamanho do JS emitido) e runtime (execução no browser/Node.js). Cada camada tem otimizações específicas.

1. Otimização do tsconfig.json

Flags essenciais para compilação rápida

// tsconfig.json — configuração otimizada
{
  "compilerOptions": {
    // Paralelismo e cache
    "isolatedModules": true,       // permite compilação paralela (obrigatório com esbuild/SWC)
    "incremental": true,           // recompila apenas o que mudou
    "tsBuildInfoFile": ".tsbuildinfo",

    // Pula verificações desnecessárias
    "skipLibCheck": true,          // ignora .d.ts de node_modules (~30% mais rápido)
    "skipDefaultLibCheck": true,

    // Módulos otimizados
    "moduleResolution": "bundler", // resolução moderna para bundlers
    "verbatimModuleSyntax": true,  // force `import type` — elimina imports do emit
    "module": "esnext",

    // Target moderno = JS menor
    "target": "es2022",            // async/await nativo, sem polyfills
    "lib": ["es2022", "dom", "dom.iterable"]
  }
}

isolatedModules: true

Essa flag permite que cada arquivo seja transpilado independentemente, sem depender de informações de outros arquivos. Isso é essencial para:

  • esbuild — 100x mais rápido que tsc para transpilação
  • SWC — usado pelo Next.js, Rust-based
  • Bun — bundler nativo em Zig
// ❌ Com isolatedModules, isso gera erro:
const enum Direction { Up, Down } // const enum não pode ser usado entre arquivos

// ✅ Use as const assertion:
const Direction = { Up: 0, Down: 1 } as const;

2. Tree Shaking e Bundle Size

verbatimModuleSyntax + import type

O TypeScript 5.0+ introduziu verbatimModuleSyntax que substitui importsNotUsedAsValues. Ele força que imports de tipos usem import type, garantindo que sejam eliminados do JavaScript emitido.

// ❌ Import de tipo sem `type` — pode ser incluído no bundle
import { User, ApiResponse } from './types';

// ✅ Import de tipo — eliminado pelo bundler
import type { User, ApiResponse } from './types';

// ✅ Mix: tipos com `type`, valores sem
import { UserService } from './services';
import type { User, ApiResponse } from './types';

Barrel exports e tree shaking

Barrel files (index.ts com export *) podem impedir tree shaking. O bundler não consegue eliminar exports não usados quando tudo passa por um barrel.

// ❌ index.ts — barrel que impede tree shaking
export * from './userService';
export * from './orderService';
export * from './paymentService'; // mesmo que só userService seja usado, tudo é incluído

// ✅ Imports diretos — bundler elimina o que não é usado
import { UserService } from './userService';

// ✅ Barrel com exports nomeados (melhor que wildcard)
export { UserService } from './userService';
export { OrderService } from './orderService';

const enum vs enum vs as const

// ❌ enum — gera objeto IIFE no runtime (~100 bytes)
enum Direction { Up, Down, Left, Right }

// ✅ const enum — inlined pelo compilador, zero runtime
// Porém: não funciona com isolatedModules
const enum Direction { Up, Down, Left, Right }

// ✅✅ as const — zero runtime, funciona com isolatedModules, tree-shakeable
const Direction = { Up: 0, Down: 1, Left: 2, Right: 3 } as const;
type Direction = (typeof Direction)[keyof typeof Direction];

preserveConstEnums + isolatedModules

// tsconfig.json
{
  "compilerOptions": {
    "isolatedModules": true,
    "preserveConstEnums": false  // remove const enums do emit
  }
}

3. Compilation speed — Projeto TypeScript Nativo em Go

Em março de 2025, Anders Hejlsberg anunciou o port nativo do TypeScript para Go. Este é o maior projeto de performance da história do TypeScript.

Benchmarks reais

CodebaseLinhas de códigotsc atual (JS)TS nativo (Go)Speedup
VS Code1.505.00077,8s7,5s10.4x
Playwright356.00011,1s1,1s10.1x
TypeORM270.00017,5s1,3s13.5x

Benefícios além da compilação

  • Editor: load de 9.6s → 1.2s no repositório do VS Code (8x mais rápido)
  • Memória: ~50% de redução no uso de RAM
  • Type checking paralelo: aproveita todos os cores da CPU
  • LSP nativo: comunicação mais rápida com editores

Cronograma

  • TypeScript 6.x — release de transição (JS, com deprecations para preparar o 7.0)
  • TypeScript 7.0 — port nativo em Go, 100% compatível com a linguagem atual
  • Preview disponível: npm install @typescript/native-preview
  • Repositório: microsoft/typescript-go

4. Project References para monorepos

Para projetos grandes, project references permitem compilar apenas o que mudou, em ordem correta.

// tsconfig.json (raiz)
{
  "references": [
    { "path": "./packages/shared" },
    { "path": "./packages/api" },
    { "path": "./packages/web" }
  ],
  "compilerOptions": { "composite": true }
}
# Compila apenas pacotes alterados
tsc --build --incremental

# Compila em paralelo (TS 5.0+)
tsc --build --force

5. Runtime performance

Evite Object.keys() em loops quentes

// ❌ Aloca array a cada iteração
for (const key of Object.keys(config)) { /* ... */ }

// ✅ Cacheie as keys
const keys = Object.keys(config);
for (const key of keys) { /* ... */ }

// ✅✅ Use for...in com hasOwnProperty
for (const key in config) {
  if (Object.prototype.hasOwnProperty.call(config, key)) { /* ... */ }
}

Lazy imports para code splitting

// ❌ Import estático — carrega tudo no bundle inicial
import { HeavyChart } from './HeavyChart';

// ✅ Dynamic import — carrega apenas quando necessário
const HeavyChart = lazy(() => import('./HeavyChart'));

// ✅✅ Preload no hover — carrega antes do clique
const loadChart = () => import('./HeavyChart');
<a href="/chart" onMouseEnter={loadChart}>Ver gráfico</a>

Map sobre Array para lookups

// ❌ O(n) — percorre array toda vez
const user = users.find(u => u.id === targetId);

// ✅ O(1) — lookup instantâneo
const userMap = new Map(users.map(u => [u.id, u]));
const user = userMap.get(targetId);

6. Ferramentas de análise

FerramentaO que fazComando
tsc --generateTraceGera trace de performance do compiladortsc --generateTrace ./trace
source-map-explorerVisualiza bundle por módulonpx source-map-explorer dist/*.js
webpack-bundle-analyzerVisualiza bundle webpackPlugin no next.config.js
@typescript/analyze-traceAnalisa trace do tscnpx @typescript/analyze-trace ./trace
knipEncontra exports/imports mortosnpx knip
ts-unused-exportsEncontra exports não usadosnpx ts-unused-exports tsconfig.json

7. TypeScript 6.0 — Mudanças de performance

  • strict: true por padrão — catches bugs cedo, reduz debugging
  • --stableTypeOrdering — ordenação determinística de tipos (preparação para TS 7.0 paralelo)
  • --target es2025 — JS emitido é mais moderno e menor
  • Deprecated --outFile — concatenar tudo em um arquivo impede tree shaking
  • Deprecated --moduleResolution classic/node10 — resolução lenta

Referências

On this page