Introdução: por que a refatoração de código legado não é um luxo, mas uma necessidade
\nNo desenvolvimento web moderno, o TypeScript se tornou o padrão de facto para grandes projetos. No entanto, muitas empresas e startups enfrentam um problema: a base de código escrita em JavaScript puro ou versões antigas e não rigorosas do TypeScript, com o tempo, se transforma em um "pântano". A falta de tipos, funções inchadas, dependências implícitas e padrões obsoletos — tudo isso retarda o desenvolvimento e aumenta o número de bugs.
\nA refatoração de código legado é o processo de melhorar a estrutura interna de um programa sem alterar seu comportamento externo. No contexto do TypeScript, isso adquire um valor especial: não apenas limpamos o código, mas também obtemos um poderoso sistema de tipos que previne erros em tempo de compilação. Neste artigo, vamos detalhar um plano passo a passo de refatoração, desde a análise inicial até os testes finais, com exemplos reais em TypeScript.
\n\n1. Análise e inventário: por onde começar?
\nO primeiro e mais importante passo é entender com o que estamos lidando. Não se pode simplesmente pegar e reescrever tudo de uma vez. Isso é o caminho para o caos e o tempo perdido. A abordagem correta é realizar uma auditoria da base de código.
\n- \n
- Identifique os "pontos críticos". Encontre os módulos que são alterados com mais frequência ou que contêm mais bugs. Use ferramentas como
git logou SonarQube. \n - Descubra tipos implícitos. No código JS legado, é comum encontrar funções que aceitam
anyou usam@ts-ignore. Faça uma lista desses locais. \n - Verifique as dependências. Bibliotecas desatualizadas (por exemplo,
lodash3.x) podem atrapalhar a transição para APIs modernas do TypeScript. \n - Escreva testes. Antes de qualquer refatoração, cubra as áreas-chave do código com testes. Esta é a sua "rede de segurança". \n
Exemplo: você tem uma função em JS que processa dados do usuário. Em vez de reescrevê-la imediatamente, adicione testes unitários com Jest ou Vitest:
\n// legacy.js\nfunction processUser(data) {\n return { name: data.name, age: data.age + 1 };\n}\n\n// test.js\nimport { processUser } from './legacy';\ntest('processUser increments age', () => {\n expect(processUser({ name: 'Alice', age: 30 })).toEqual({ name: 'Alice', age: 31 });\n});\n\nSó depois disso você pode começar a refatoração.
\n\n2. Migração gradual para tipagem estrita
\nO TypeScript oferece vários níveis de rigor. Para código legado, recomenda-se começar com "strict": false e aumentar gradualmente o nível. Ativar todas as opções de uma vez pode quebrar centenas de arquivos.
Passos principais:
\n- \n
- Ative
noImplicitAny. Isso forçará você a especificar explicitamente os tipos para todos os parâmetros e valores de retorno. No início pode ser doloroso, mas é assim que você encontrará os lugares mais perigosos. \n - Use
strictNullChecks. Uma das principais causas de bugs sãonulleundefined. Esta flag forçará você a tratá-los explicitamente. \n - Adicione
noUnusedLocalsenoUnusedParameters. Eles ajudarão a remover código morto. \n
Exemplo de refatoração de uma função com tipos implícitos:
\n// Antes da refatoração (legacy JS)\nfunction calculateTotal(price, tax) {\n return price + (price * tax);\n}\n\n// Depois da refatoração (TypeScript)\ninterface PriceData {\n price: number;\n tax: number;\n}\n\nfunction calculateTotal({ price, tax }: PriceData): number {\n if (price < 0 || tax < 0) {\n throw new Error('Price and tax must be non-negative');\n }\n return price + (price * tax);\n}\n\nObserve: não apenas adicionamos tipos, mas também tornamos a API mais segura, usando uma interface e validação.
\n\n