TypeScript no frontend é um desses assuntos que divide equipe. Tem o desenvolvedor que usa e jura que nunca mais volta. Tem o que resiste porque “JavaScript é JavaScript e funciona”. Tem o gestor técnico no meio tentando decidir se vale a curva de aprendizado num projeto que já está atrasado.
Vou dar a perspectiva de quem usou JavaScript puro por muito tempo, migrou para TypeScript com resistência, e hoje coloca TypeScript como padrão em qualquer projeto novo que toca.
Não por modinha.
A conversa que muda de patamar é com o editor
Antes de falar em bugs que TypeScript previne, tem algo mais imediato que muda no dia a dia: a experiência de trabalhar no código.
Autocomplete que funciona de verdade. Não o autocomplete de editor que tenta adivinhar com base no que está no arquivo atual. O autocomplete que sabe que aquela função espera um objeto com um campo status, que esse status só aceita os valores “approved” ou “rejected”, e que se você tentar passar um “Approved” com A maiúsculo ele vai te avisar antes de você salvar, antes de você rodar, antes de o usuário encontrar. Isso parece pequeno. Não é. Em projetos com dez mil linhas e seis pessoas mexendo, o tempo que vai para “como é mesmo o nome desse campo?” ou “essa função aceita null aqui ou não?” é muito maior do que a maioria estima. TypeScript responde essas perguntas sem você precisar abrir o arquivo de origem ou lembrar de uma convenção que foi discutida num standup de seis meses atrás.
O bug que você vai agradecer por não ter em produção
Olha, null. Sempre null.
Já perdi conta de quantos bugs em produção vieram de algo que deveria ter um valor e estava undefined. A API retornou um objeto sem o campo esperado porque a resposta veio de um endpoint diferente do previsto. O cache devolveu um valor antigo sem o atributo que foi adicionado na versão mais recente. O componente recebeu uma prop que podia ser undefined, mas o código assumia que sempre estava lá.
Com a opção strictNullChecks, que eu ligo em todo projeto sem exceção, o compilador te força a lidar com a possibilidade de null antes de usar o valor. Você não esquece. Você não consegue esquecer. Inicialmente isso irrita bastante, porque parece que você está resolvendo problemas que não existiam. Você estava. Só que esses problemas apareciam em produção, às 23h, quando o cliente encontrava exatamente o caso específico que o teste não cobria.
A questão não é se o erro ia acontecer. É quando.
O que não vai melhorar só porque você adotou TypeScript
Tem uma ilusão de que TypeScript resolve tudo. Não resolve.
Tipagem mal feita é pior que sem tipagem. “any” em todo lugar equivale a JavaScript sem as vantagens, mas com mais verbosidade e uma falsa sensação de segurança. Já vi projeto que era formalmente TypeScript, com .ts em todo arquivo, e any espalhado por toda parte porque a equipe não queria investir o tempo necessário para tipar direito. É pior. Você não tem os benefícios e ainda tem o overhead.
Arquitetura ruim continua ruim com tipos. Componentes gigantes que fazem dez coisas, estado compartilhado por toda a árvore, acoplamento entre módulos que não deveriam se conhecer. TypeScript não conserta isso. E a curva de aprendizado para aproveitar de verdade existe, não vou mentir. Generics, utility types, narrowing correto quando você tem união de tipos. Tem uma fase onde o desenvolvedor está brigando com o compilador ao invés de trabalhar com ele. Nessa fase a produtividade cai antes de subir.
Se você coloca TypeScript num projeto sem investir em fazer certo, vai ter custo sem benefício.
Migração de JavaScript para TypeScript num projeto existente
Essa é a pergunta que aparece mais: já tenho um projeto grande em JavaScript, compensa migrar?
Depende de quanto tempo o projeto vai durar. Depende de quem vai mexer. Depende de quanto o frontend ainda vai crescer.
A boa notícia é que você não precisa migrar tudo de uma vez. TypeScript e JavaScript coexistem no mesmo projeto sem problema. Você começa pelos arquivos que mudam com mais frequência, pelos que têm mais colaboração, pelos que já causaram mais problema em produção. A migração incremental funciona e é o caminho que eu recomendo na maioria dos casos.
Aliás, um padrão que eu vejo frequentemente: a equipe pega os arquivos utilitários simples e migra logo porque são menores e mais fáceis. E fica com os arquivos críticos, os componentes que todo mundo mexe, em JavaScript ainda por meses. É exatamente ao contrário do que faz sentido. O arquivo mais crítico que muda toda semana vale mais na fila de migração do que trinta arquivos estáveis que ninguém toca há um ano.
Se o seu frontend está crescendo, se tem mais de uma pessoa mexendo, se o projeto vai durar mais de um ano: a pergunta não é se vale o investimento. É se você quer pagar esse custo agora, quando a base ainda é menor, ou depois, quando já tem débito acumulado e a migração vai custar três vezes mais.
Gabriel Schunck está disponível para consultorias e projetos de frontend e sistemas sob medida. Se você está definindo a stack do seu próximo projeto e quer uma perspectiva técnica antes de comprometer, entra em contato pelo gabriels.dev.br.