Refatoração de código legado em TypeScript: técnicas avançadas

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Por que o código legado em TypeScript exige uma abordagem especial

Trabalhar com código legado é uma realidade inevitável para qualquer desenvolvedor, especialmente em projetos grandes. Muitas vezes, esse código foi escrito sem tipagem estrita, usando any em cada esquina, e representa um emaranhado confuso de dependências. Uma simples refatoração não funciona aqui — é necessária uma abordagem sistêmica e avançada.

Neste artigo, exploraremos estratégias de refatoração de código legado em TypeScript que vão além dos guias básicos. Você aprenderá como introduzir tipagem estrita com segurança, isolar mudanças usando padrões e aproveitar os recursos do compilador para automatizar tarefas rotineiras.



Estratégia 1: Introdução gradual de tipagem estrita através de "pontes de tipo"

Um dos principais problemas do código legado é o uso total de any. Tentar substituir todos os any por tipos específicos de uma só vez resultará em centenas de erros e paralisará o desenvolvimento. Em vez disso, usamos a técnica de "pontes de tipo".

A essência do método: não reescrevemos o módulo inteiro de uma vez, mas criamos tipos-pontes intermediários que gradualmente substituem o any.



Exemplo: Tipagem de um módulo "cinza"

Suponha que temos um módulo antigo para trabalhar com usuários:

// legacyModule.tsexport function processUser(data: any): any {  // ... muito código ilegível  return { id: data.id, name: data.name, age: data.age };}

Em vez de tipar a função inteira imediatamente, criamos UserData e User:

// types.tsexport interface UserData {  id: number;  name: string;  age?: number; // campo pode estar ausente}

export interface User { id: number; fullName: string; isAdult: boolean;}

Agora usamos esses tipos, mas mantemos a assinatura antiga para compatibilidade reversa:

// legacyModule.ts (refatoração passo 1)import { UserData, User } from './types';

export function processUser(data: UserData): User { const isAdult = data.age ? data.age >= 18 : false; return { id: data.id, fullName: data.name, isAdult, };}

// Assinatura antiga para compatibilidadeexport function processUserLegacy(data: any): any { return processUser(data as UserData);}

Depois que todos os consumidores migrarem para a nova função, removemos processUserLegacy. Essa abordagem minimiza o risco de quebrar dependências.



Estratégia 2: Isolamento de dependências "sujas" com o padrão "Adapter"

O código legado frequentemente está fortemente acoplado a bibliotecas externas, estados globais ou APIs obsoletas. Para realizar a refatoração com segurança, é necessário isolar essas dependências. A melhor ferramenta para isso é o padrão "Adapter" combinado com interfaces.



Exemplo: Isolamento de uma API obsoleta

// oldApi.ts (legado)export function fetchOldData(callback: (data: any) => void): void {  // API antiga com callbacks  setTimeout(() => callback({ value: 42 }), 100);}

Criamos uma interface para a nova abordagem (baseada em Promise) e um adaptador:

// apiAdapter.tsimport { fetchOldData } from './oldApi';

export interface IDataFetcher { fetchData(): Promise<{ value: number }>;}

export class LegacyApiAdapter implements IDataFetcher { fetchData(): Promise<{ value: number }> { return new Promise((resolve, reject) => { fetchOldData((data) => { if (data) { resolve(data); } else { reject(new Error('No data')); } }); }); }}

Agora todo o código novo usa IDataFetcher. Quando você reescrever completamente a API antiga, precisará apenas substituir a implementação do adaptador, sem tocar no restante do código. Isso reduz o risco de regressão ao mínimo.



Estratégia 3:

Blogs

Book Recommendations