Introdução: Por que "só compila" é um critério ruim
Imagine a situação: você abre um Pull Request no GitHub, vê o sinal verde do CI e ouve uma voz interior: "Os tipos coincidem — então o código está correto". Familiar? Se sim, você está caindo na armadilha que chamamos de "falsa sensação de segurança do TypeScript".
TypeScript não é uma panaceia. Ele não captura erros lógicos, não verifica requisitos de negócio e certamente não garante que seu código não quebrará em tempo de execução. É por isso que o code review em TypeScript não é sobre "passar os olhos", mas sobre uma abordagem sistemática. Neste artigo, contarei no que realmente vale a pena prestar atenção ao revisar código TypeScript. Eu mantenho um blog no PythonLib, e aqui estamos acostumados a cavar fundo — prepare-se.
1. Tipo any: a bandeira vermelha
A coisa mais óbvia, mas por algum motivo a mais frequente. any é o interruptor do TypeScript. Se você vê any no código, sua tarefa é entender: é preguiça do autor ou um caso realmente justificado?
Exemplo ruim:
function processData(data: any) { return data.name.toLowerCase();}Aqui perdemos toda a informação sobre o tipo. Se data vier como null ou undefined — olá, erro em tempo de execução.
Exemplo bom:
interface UserData { name: string; age?: number;}
function processData(data: UserData) { return data.name.toLowerCase();}O que verificar no code review: Se any ainda for usado (por exemplo, para trabalhar com JSON de estrutura desconhecida), o autor exige validação na entrada? Frequentemente, any mascara a ausência de tipagem adequada para dados externos.
2. Strict mode: não o desative
A primeira coisa que verifico no tsconfig.json é a flag strict: true. Se não estiver, você está perdendo uma camada inteira de verificações: strictNullChecks, noImplicitAny, strictFunctionTypes e outras.
Sem strictNullChecks, você pode escrever:
const user = getUser(); // pode retornar nullconst name = user.name; // TS não reclamará, mas em tempo de execução quebraráNo code review: Se você perceber que o projeto está rodando sem strict mode — soe o alarme. Isso é dívida técnica que se acumula exponencialmente. É melhor gastar um dia ativando o strict mode e corrigindo erros do que um mês caçando bugs em produção.
3. Genéricos: poder e responsabilidade
Genéricos são o superpoder do TypeScript. Mas com grandes poderes vêm grandes responsabilidades. No code review, sempre vejo: o autor complicou demais os tipos?
Exemplo de complexidade excessiva:
function identity<T extends Record<string, unknown>>(arg: T): T { return arg;}Por que restringir T a Record<string, unknown> se estamos apenas retornando o mesmo? Basta:
function identity<T>(arg: T): T { return arg;}O que verificar:
- Os genéricos estão sendo usados onde é necessária flexibilidade, ou daria para usar um tipo específico?
- Não há restrições (extends) excessivas que atrapalhem a reutilização?
- Os tipos foram inferidos corretamente — o usuário não precisa especificar manualmente
<SomeType>onde o TS poderia deduzir sozinho?
4. unknown vs any: escolha a arma certa
Ao trabalhar com dados cujo tipo você desconhece (API, localStorage, entrada do usuário), use unknown, não any. unknown força você a verificar explicitamente o tipo antes de usar.
Ruim:
<