Checklist de code review em TypeScript | Guia prático
Um code review em TypeScript precisa ir além de erros de sintaxe, nomes de variáveis ou detalhes que o linter já deveria pegar.
Quando você revisa um PR em TypeScript, não basta verificar se o código compila. O mais importante é entender se os tipos representam bem os dados e se os contratos criados pelo código são seguros de usar.
Esse é um ponto em que muitos problemas passam despercebidos.
TypeScript ajuda a reduzir erros, mas não elimina decisões ruins de tipagem. O código pode estar correto para o compilador e ainda assim esconder contratos frágeis, suposições incorretas ou comportamentos inesperados em runtime.
Este guia traz um checklist prático para revisar código TypeScript com mais atenção aos pontos que realmente importam e que podem acabar virando bugs em produção.
Para uma visão mais ampla sobre revisão em JavaScript, veja também o guia de boas práticas para code review em JavaScript.
O que revisar em um PR TypeScript?
Em um PR TypeScript, alguns pontos merecem atenção especial: segurança de tipos, uso de any, type assertions, tratamento de null e undefined, contratos públicos e validação de dados externos.
Dependendo do projeto, isso também inclui props em React, entradas de aplicações Node.js e os dados usados nos testes.
Um bom ponto de partida é este checklist:
- O uso de
anyestá justificado? - O valor deveria começar como
unknown? - Algum
as Typeestá escondendo uma incompatibilidade real? - Funções exportadas têm contratos claros?
- Valores nullable são tratados corretamente?
- Os tipos permitem estados que não deveriam existir?
- Dados externos são validados antes de serem usados?
- Props e eventos em React estão bem tipados?
- Variáveis de ambiente são validadas na inicialização?
- Testes usam dados compatíveis com os tipos reais?
Essas verificações já cobrem boa parte dos problemas específicos de TypeScript que costumam escapar em um review.
Por que code review em TypeScript precisa de um checklist próprio?
TypeScript muda parte do que você precisa procurar durante o review.
O compilador já consegue identificar muitos problemas antes do código chegar ao PR. O que ele não consegue dizer é se os tipos realmente representam o comportamento do sistema.
Considere este código:
const user = response.data as User;
Para o TypeScript, user agora é um User. Mas nenhum dado foi validado.
Se a API retornar algo diferente do contrato esperado, o erro continua existindo mesmo que o código compile normalmente.
Por isso, durante o review, é preciso ir além de “isso está tipado?” e perguntar se aquele tipo realmente pode ser garantido naquele ponto do código.
Como revisar o uso de any em TypeScript?
any merece atenção porque remove boa parte das garantias que TypeScript deveria oferecer naquele trecho.
Isso não significa que todo any seja necessariamente um problema. Existem casos em que ele é inevitável ou temporariamente aceitável. O importante é entender por que ele está sendo usado.
Durante o review, verifique se:
- existe uma limitação real da biblioteca ou integração
- o uso é temporário e está bem isolado
unknownseria uma alternativa mais segura- existe um tipo mais específico que poderia ser usado
O principal risco é deixar o any se espalhar pelo código. A partir dali, propriedades podem ser acessadas e valores podem ser passados adiante sem que o compilador consiga verificar muita coisa.
Quando o formato do valor ainda é desconhecido, especialmente em dados externos, unknown costuma expressar melhor essa situação.
Quando usar unknown em vez de any?
Use unknown quando o código recebe um valor cujo formato ainda não foi verificado.
Isso aparece com frequência em respostas de API, requests, webhooks, mensagens de fila, arquivos ou qualquer outra entrada externa.
A diferença importante é que unknown obriga o código a validar ou fazer narrowing antes de usar o valor.
function isUser(value: unknown): value is User {
return (
typeof value === "object" &&
value !== null &&
"id" in value &&
"email" in value
);
}
Isso deixa explícita a fronteira entre um dado desconhecido e um valor que o restante da aplicação pode tratar como confiável.
Durante o review, vale procurar principalmente os lugares em que dados externos entram no sistema já tratados como tipos internos.
Como revisar type assertions em TypeScript?
Type assertions como as User não validam nem transformam o valor. Elas apenas dizem ao compilador qual tipo assumir.
Por isso, merecem atenção especial durante o review.
Existem situações em que uma assertion faz sentido, principalmente quando o código realmente sabe algo que o TypeScript não consegue inferir. O problema é quando ela vira uma forma rápida de contornar um erro de tipo.
const user = response.data as User;
Se response.data vem de uma fonte externa, o as User não garante que o valor tenha aquele formato.
Nesses casos, prefira validação real:
const user = UserSchema.parse(response.data);
Ou um type guard equivalente.
Durante o review, tente entender se a assertion está documentando uma garantia real do código ou apenas escondendo uma incerteza.
Como revisar null e undefined em TypeScript?
Projetos TypeScript se beneficiam bastante de strictNullChecks, porque ele obriga o código a tratar null e undefined de forma explícita.
No review, o mais importante é verificar se a ausência de valor faz parte do contrato e se ela está sendo tratada de forma coerente.
Optional chaining pode simplificar acessos seguros:
return user?.profile?.name;
E ?? costuma ser a escolha correta quando o fallback deve acontecer apenas para null ou undefined:
const displayName = user.profile?.name ?? "Anonymous";
Também vale observar usos de || em valores que podem aceitar 0, false ou string vazia.
A pergunta principal é se o código diferencia ausência de um valor válido que apenas acontece de ser falsy.
Como revisar tipos de API em TypeScript?
Uma API bem tipada deve deixar claro como pode ser usada e reduzir a quantidade de estados ou chamadas inválidas possíveis.
Quando revisar uma função exportada, hook, componente ou pacote compartilhado, vale olhar primeiro para a assinatura.
export function buildReviewSummary(
pullRequest: PullRequest,
comments: ReviewComment[]
): ReviewSummary {
// ...
}
Ela mostra o que entra, o que sai e qual contrato outras partes da aplicação vão depender.
Tipos de retorno explícitos podem ser especialmente úteis em APIs públicas ou compartilhadas, porque evitam que mudanças internas alterem o contrato sem intenção.
Também vale revisar se os tipos têm nomes que representam bem o domínio. Nomes genéricos como Data, Item, Info ou Payload tendem a perder significado conforme o projeto cresce.
O objetivo não é tornar todos os tipos mais verbosos, e sim deixar o contrato compreensível para quem vai usá-lo depois.
Como revisar props em React com TypeScript?
Em React, o principal ponto não é apenas conferir se as props têm tipos, mas se esses tipos representam corretamente os estados que o componente pode assumir.
Um sinal comum de problema é um componente com vários booleanos relacionados entre si:
<Button isPrimary isDestructive isIconOnly />
Dependendo do comportamento esperado, essas props podem permitir combinações que não fazem sentido.
Em alguns casos, uma união deixa o contrato mais claro:
type ButtonVariant = "primary" | "destructive" | "icon";
type ButtonProps = {
variant: ButtonVariant;
children?: React.ReactNode;
};
Durante o review, também vale observar:
- props opcionais que deveriam ser obrigatórias
- callbacks definidos como
Function - handlers que caíram em
any - estados nullable sem tipo claro
- hooks que retornam estruturas difíceis de entender
A pergunta mais útil aqui é: o tipo ajuda a impedir estados inválidos ou apenas descreve qualquer combinação possível?
Como revisar erros em TypeScript?
Valores capturados em um catch não devem ser tratados automaticamente como Error.
Em JavaScript, qualquer valor pode ser lançado. Por isso, o código precisa fazer narrowing antes de acessar propriedades específicas.
try {
await runImport();
} catch (err: unknown) {
if (err instanceof Error) {
console.error(err.message);
} else {
console.error("Unknown import failure");
}
}
Isso importa principalmente em código que registra erros, cria mensagens para usuários ou envia informações para ferramentas de observabilidade.
Durante o review, verifique se o tratamento de erro preserva o problema original em vez de criar uma nova falha ao tentar acessá-lo.
Como revisar código Node.js em TypeScript?
No backend, muitos problemas aparecem justamente nas fronteiras do sistema.
O código interno pode estar bem tipado, mas requests, webhooks, filas, variáveis de ambiente e serviços externos continuam sendo dados de runtime.
Por isso, revise com atenção:
- request body
- query e route params
- headers
- webhooks
- mensagens de fila
- variáveis de ambiente
- respostas de serviços externos
Evite confiar apenas em assertions como:
const input = req.body as CreateUserInput;
Quando possível, valide a entrada antes de usá-la:
const input = CreateUserSchema.parse(req.body);
O mesmo vale para configuração. Se uma variável de ambiente é obrigatória, é melhor descobrir isso durante a inicialização da aplicação do que apenas quando uma determinada rota for executada.
Como revisar generics em TypeScript?
Generics são úteis quando existe uma abstração que realmente precisa funcionar com diferentes tipos.
O problema aparece quando o generic cria uma garantia que o runtime não consegue cumprir.
async function fetchData<T>(url: string): Promise<T> {
const response = await fetch(url);
return response.json() as Promise<T>;
}
Nesse caso, T não foi validado. O chamador escolhe o tipo, mas nada garante que a resposta tenha aquele formato.
Uma alternativa é fazer a função receber a lógica de validação:
async function fetchData<T>(
url: string,
parse: (value: unknown) => T
): Promise<T> {
const response = await fetch(url);
const data: unknown = await response.json();
return parse(data);
}
No review, observe os dois extremos: código duplicado que poderia se beneficiar de uma abstração e generics complexos demais para um problema simples.
A abstração precisa reduzir complexidade, não apenas deslocá-la.
Como revisar testes em projetos TypeScript?
Os tipos usados nos testes também precisam representar a realidade do código.
Um padrão que merece atenção é usar assertions apenas para montar fixtures incompletas:
const user = {
id: "1"
} as User;
Isso permite que o teste ignore campos que o código real considera obrigatórios.
Builders e factories costumam ser uma alternativa melhor porque mantêm os dados de teste compatíveis com os contratos da aplicação.
function createUser(overrides: Partial<User> = {}): User {
return {
id: "user-1",
email: "user@example.com",
name: "Test User",
...overrides
};
}
Também vale conferir se existem testes para entradas inválidas quando o código lida com dados externos.
TypeScript ajuda a garantir o que acontece dentro do sistema. Ele não impede que uma API, webhook ou usuário envie um valor inesperado.
Checklist completo de code review em TypeScript
Nem todo item será relevante para todo PR, mas este checklist pode servir como referência durante a revisão.
Tipagem e correção
anyfoi usado? Existe um motivo claro?unknownseria mais adequado para dados ainda não validados?- Type assertions estão escondendo incompatibilidades?
- Existem parsers ou type guards nas fronteiras certas?
- Funções públicas têm contratos claros?
- Valores nullable são tratados corretamente?
??seria mais adequado do que||?- Os tipos impedem estados inválidos?
- Os tipos representam os dados reais?
APIs e contratos
- A assinatura deixa claro como a função deve ser usada?
- Os nomes dos tipos representam bem o domínio?
- Tipos compartilhados têm fronteiras claras?
- Mudanças internas podem alterar contratos públicos sem intenção?
- A API permite combinações ou estados inválidos?
- Dados externos são validados antes de entrarem no domínio?
React
- Props estão bem tipadas?
- Props opcionais são realmente opcionais?
- Event handlers evitam
any? - Estados nullable têm tipo explícito quando necessário?
- Hooks retornam estruturas claras?
- O modelo de tipos evita combinações inválidas?
Node.js e backend
- Request body é validado antes do uso?
- Params são convertidos e validados?
- Variáveis de ambiente são verificadas na inicialização?
- Webhooks e filas são tratados como dados externos?
- Tipos do banco acompanham o schema real?
- Erros são tratados com narrowing antes do acesso?
Testes
- Fixtures respeitam os tipos reais?
- Assertions estão sendo usadas para esconder dados incompletos?
- Entradas inválidas estão cobertas?
- Mocks representam contratos próximos dos reais?
- Tipos mais complexos precisam de testes específicos de tipagem?
Como dar feedback em um PR TypeScript?
Um bom comentário de review explica o risco em vez de apenas apontar que algo parece errado.
Em vez de:
This is confusing.
Um comentário mais útil seria:
This casts response.data as User, but the value comes from an external API.
Can we parse it before returning from the API client?
Nesse caso, o autor entende por que aquilo importa e qual mudança quem está revisando está sugerindo.
Também pode ajudar separar comentários que bloqueiam o merge de sugestões menores, desde que o time tenha uma convenção clara para isso.
O objetivo não é classificar tudo. É evitar que um detalhe de estilo pareça ter a mesma importância de um bug ou de um contrato inseguro.
Como preparar um PR TypeScript para review?
Antes de pedir review, rode as verificações automáticas que já fazem parte do projeto.
Por exemplo:
tsc --noEmit
eslint .
prettier --check .
Os comandos podem variar entre repositórios. O importante é não deixar para o quem revisa problemas que o compilador, o linter ou a CI conseguem encontrar sozinhos.
A descrição do PR também ajuda bastante.
Se a mudança altera um contrato público, adiciona uma validação importante ou muda a forma como algum dado é representado, deixe isso claro.
Uma boa descrição ajuda quem vai revisar a entender:
- qual problema está sendo resolvido
- quais contratos mudaram
- quais entradas ou integrações foram afetadas
- onde vale prestar mais atenção durante o review
Quanto mais contexto existe antes de abrir o diff, menos tempo o a pessoa precisa gastar reconstruindo a intenção da mudança.
Um bom review em TypeScript reduz surpresa em produção
O principal papel do TypeScript é tornar contratos explícitos. O papel do review é verificar se esses contratos realmente fazem sentido.
Os tipos representam os dados reais? O código evita estados inválidos? Entradas externas são validadas antes de serem tratadas como confiáveis?
Quando o review olha para esses pontos, ele encontra uma classe de problema que o compilador sozinho não consegue resolver.
Um bom review em TypeScript não busca apenas código que passe no tsc. Ele busca código em que os tipos continuem verdadeiros quando a aplicação encontra o mundo real.