Como Otimizar a Performance em TypeScript: Guia Prático

Como Otimizar a Performance em TypeScript: Guia Prático





Como otimizar performance em TypeScript



O que mais impacta: build time e bundling

Sou meticulous quanto ao impacto de configuração de build. Em projetos TypeScript grandes, pequenas escolhas de tsconfig podem resultar em redução de tempo de compilação e de geração de bundle. Abaixo estão as práticas que realmente entregam ganhos reais sem comprometer a qualidade do código.

  • Incremental builds para recompilar apenas o que mudou, reduzindo drasticamente o tempo de compilação em grandes bases.
  • Isolated modules e importHelpers para reduzir duplicação de código helper gerado pelo TypeScript.
  • skipLibCheck para evitar checagem de tipos em dependências de terceiros, acelerando o build em projetos grandes.
  • downlevelIteration para manter compatibilidade com estruturas iteráveis em ambientes mais antigos sem impactar negativamente a performance em runtime.
  • tsBuildInfoFile para armazenar informações de compilação entre builds incrementais, mantendo o cache consistente.
  • Target moderno e módulo alinhado ao bundler (ESNext/ES2015+ com tree-shaking) para reduzir o tamanho do bundle.

A seguir, um conjunto recomendado de opções para tsconfig.json. Adapte conforme seu ambiente (Node vs browser) e seu bundler.


{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "strict": true,
    "incremental": true,
    "tsBuildInfoFile": "./.tsbuildinfo",
    "isolatedModules": true,
    "importHelpers": true,
    "downlevelIteration": true,
    "skipLibCheck": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true
  }
}
  

Dicas rápidas: use um bundler moderno (Vite, esbuild, Webpack com Terser) para aproveitar o ESNext e o tree-shaking definido pelo tsconfig.

Tipagem eficiente para runtime

A tipagem do TypeScript é essencial para segurança de código, mas o benefício de performance vem principalmente de como você usa tipos no código gerado. A seguir, práticas que ajudam sem introduzir overhead de runtime.

  • Importações apenas de tipos quando possível: use import type para evitar trazer símbolos de tempo de execução desnecessários.
  • Discriminated unions para reduzir checks de tipo manuais em caminhos comuns de código.
  • Evite using de ‘any’ desnecessário; prefira ‘unknown’ com guards para manter a segurança sem perder performance.

Exemplo prático (importação de tipos):


import type { User } from "./types";

async function fetchUsers(): Promise<User[]> {
  const res = await fetch("/api/users");
  return res.json() as Promise<User[]>;
}
  

Práticas de código para runtime lean

Performance em runtime decorre de escolhas no código gerado pelo TypeScript e pelo resultado do bundler. Abaixo, padrões que ajudam sem precisar de hacks complexos.

  • Limite alocação dentro de loops: prefira reutilizar arrays/objetos quando possível, evitando novas instâncias a cada iteração.
  • Minimize boxing e acessos dinâmicos de propriedades em hot paths.
  • Cache de referências repetidas: armazene propriedades e funções usadas com frequência em variáveis locais.
  • Habilite importHelpers para reduzir duplicação de código helper gerado pelo TypeScript (quando usar tslib).

Exemplo de configuração opcional para reduzir overhead de helpers:


{
  "compilerOptions": {
    "importHelpers": true,
    "downlevelIteration": true
  }
}
      

Benchmark, profiling e monitoramento

Teste suas mudanças com benchmarks simples e controle de tempo para validar ganhos reais. Use ferramentas de profiling no runtime (Node ou browser) para confirmar impacto.

  • Node: use perf_hooks para medir tempos com precisão.
  • Browser: use performance.now() para medições simples, ou ferramentas de browser performance/profile.
  • Compare antes/depois com cenários realistas e dados de produção simulados.

Exemplo rápido de benchmark em Node:


import { performance } from "perf_hooks";

function a(n: number): number {
  let s = 0;
  for (let i = 0; i < n; i++) s += i;
  return s;
}

function b(n: number): number {
  // uma abordagem alternativa que pode ser mais rápida dependendo do cenário
  let s = (n * (n - 1)) / 2;
  return s;
}

const iterations = 10000;
const t0 = performance.now();
for (let i = 0; i < iterations; i++) { a(1000); }
const t1 = performance.now();

const t2 = performance.now();
for (let i = 0; i < iterations; i++) { b(1000); }
const t3 = performance.now();

console.log("Tempo A:", t1 - t0, "ms");
console.log("Tempo B:", t3 - t2, "ms");
      

Demonstre ganhos com dados e mantenha um registro de mudanças para orientar decisões futuras.

Gostou deste guia? Explore mais conteúdos para aprofundar suas habilidades em desenvolvimento moderno.

Continue lendo para consolidar técnicas que entregam ganhos reais no dia a dia.