FlowingDev

TypeScript, explicado: como o JavaScript ganhou cinto de segurança e airbags

Aprenda por que o TypeScript é o JavaScript com superpoderes, adicionando tipos estáticos para pegar erros mais cedo e tornar o código mais robusto e compreensível.

Testar a ferramenta: Playground TypeScript

Em uma frase

O TypeScript é uma linguagem de programação construída em cima do JavaScript que adiciona um "sistema de tipos", que é como um corretor gramatical para seus dados que pega uma classe enorme de bugs antes mesmo do seu código rodar.

O problema que ele resolve

Imagine os primórdios da web. O JavaScript nasceu às pressas (famosamente em apenas 10 dias) para tornar as páginas web um pouco mais interativas. Ele foi projetado para scripts pequenos: animar um botão, validar um formulário. Era dinâmico, flexível e "perdoava" muita coisa. Essa flexibilidade era sua maior força e, conforme a web amadureceu, sua maior fraqueza.

No JavaScript "puro" (vanilla), uma variável pode ser o que ela quiser. Ela pode começar como um número, ser reatribuída para uma string, depois virar um objeto e, finalmente, acabar como undefined.

let myThing = 123;         // myThing é um número
myThing = "Hello world"; // Agora é uma string
myThing = { id: 456 };   // E agora, um objeto

Para um script de 20 linhas, tudo bem. Para uma aplicação de 200.000 linhas que sustenta um serviço gigante como o Google Maps ou o Figma, isso é uma receita para o caos. Os desenvolvedores passavam o tipo de dado errado para uma função, levando ao infame erro undefined is not a function em tempo de execução — ou seja, na frente de um usuário real. Refatorar código era um pesadelo; mude uma função e você pode quebrar outras dez partes da aplicação sem saber até ser tarde demais.

A Microsoft, enfrentando exatamente esse problema com seus projetos de JavaScript em larga escala, decidiu colocar um pouco de ordem no caos. Em 2012, eles lançaram o TypeScript. O objetivo não era substituir o JavaScript, mas aprimorá-lo. Ele adicionaria uma camada de segurança e previsibilidade sobre a linguagem que todo mundo já conhecia, tornando-a adequada para as aplicações gigantes e complexas que a web moderna exigia.

Como funciona por debaixo dos panos

A mágica do TypeScript acontece antes que o código chegue ao navegador. Seu browser não roda TypeScript; ele roda o bom e velho JavaScript. O trabalho do TypeScript é atuar como um linter superinteligente e proativo durante o desenvolvimento.

### O TypeScript é um Superset do JavaScript

Este é o conceito mais importante para entender. Um "superset" significa que qualquer código JavaScript válido também é um código TypeScript válido. Você pode pegar um arquivo .js, renomeá-lo para .ts e ele vai funcionar. O TypeScript apenas adiciona uma nova sintaxe por cima do JavaScript.

A adição principal são as anotações de tipo (type annotations). Agora você pode dizer ao TypeScript que tipo de dado esperar.

// Isso é JavaScript puro
function getLength(someValue) {
  return someValue.length;
}

// Isso é TypeScript
function getLengthTyped(someValue: string | any[]) {
  return someValue.length;
}

Na versão JavaScript, se você chamasse getLength(42), receberia um erro em tempo de execução, porque o número 42 não tem uma propriedade length. Na versão TypeScript, seu editor de código e o compilador gritariam com você imediatamente, dizendo que um número não é um argumento válido. O bug é pego antes mesmo de você salvar o arquivo.

### O Processo de Transpilação

Então, se os navegadores não rodam TypeScript, o que acontece com essa sintaxe extra? Ela é apagada em um processo chamado transpilação.

Transpilação é um tipo específico de compilação: uma conversão de código-fonte para código-fonte. O compilador do TypeScript (um programa geralmente chamado de tsc) lê seu arquivo .ts, verifica se há erros de tipo e, em seguida, cospe um arquivo .js limpo que qualquer navegador pode entender.

Aqui está um antes e depois:

Entrada TypeScript (.ts)

function greet(person: string, date: Date): string {
  return `Hello ${person}, today is ${date.toDateString()}!`;
}

Saída JavaScript (.js)

function greet(person, date) {
  return "Hello ".concat(person, ", today is ").concat(date.toDateString(), "!");
}

Note como as anotações de tipo (: string, : Date) sumiram completamente. O transpiler as usou para verificar seu trabalho e depois as jogou fora, deixando para trás o JavaScript executável. Um playground de TypeScript faz essa etapa de transpilação instantaneamente, direto no seu navegador, para que você possa ver o resultado em tempo real.

### Type Checking e Inferência de Tipos

O "cérebro" do TypeScript é seu type-checker. É a parte que analisa seu código e valida se os tipos se encaixam. Mas você nem sempre precisa escrever os tipos. O TypeScript é inteligente o suficiente para descobri-los na maioria das vezes através de um processo chamado inferência de tipo (type inference).

let name = "Alice"; // O TypeScript infere que `name` é do tipo `string`
let age = 30;     // O TypeScript infere que `age` é do tipo `number`

// Se você tentar isso, o TypeScript vai dar erro:
// Type 'number' is not assignable to type 'string'.
name = 42;

Você não precisou escrever let name: string = "Alice". O TypeScript viu você atribuir uma string literal e inferiu corretamente o tipo. Isso mantém seu código limpo e legível, ao mesmo tempo que oferece todos os benefícios de segurança. Você só precisa adicionar tipos explícitos quando o TypeScript não consegue descobrir por conta própria, como em parâmetros de função ou variáveis vazias.

Casos da vida real

### O Grande Refactor

O principal produto de uma startup era um monolito JavaScript gigantesco e bagunçado. A equipe inicial tinha se movido rápido e quebrado coisas, e agora a nova equipe estava pagando o pato. Eles precisavam refatorar um módulo central que lidava com as permissões de usuário. O problema? Ninguém tinha certeza de qual era o formato que o objeto user deveria ter. Ele tinha user.isAdmin ou user.role === 'admin'? O user.id vinha como um número ou uma string?

Cada mudança era uma aposta. Eles decidiram introduzir o TypeScript, arquivo por arquivo. Começaram definindo uma interface User clara:

interface User {
  id: number;
  email: string;
  role: 'admin' | 'editor' | 'viewer';
  lastLogin: Date;
}

De repente, suas IDEs acenderam como uma árvore de Natal, apontando cada lugar no código onde eles estavam usando o objeto user incorretamente. Uma função tentava acessar user.isAdmin, que não existia na nova interface. Outra passava um ID em string em vez de um número. O refactor deixou de ser um jogo de adivinhação aterrorizante para se tornar um processo sistemático e guiado.

Lição: O TypeScript transforma uma refatoração caótica em uma tarefa de engenharia segura e previsível, criando uma única fonte da verdade para suas estruturas de dados.

### O Bug Fantasma da API

Uma desenvolvedora front-end estava construindo um dashboard que exibia dados de uma API de terceiros. A documentação da API dizia claramente que o preço de um produto seria um número, como 19.99. Ela escreveu seu código TypeScript de acordo: interface Product { name: string; price: number; }.

Seu código funcionou perfeitamente por semanas, até que um dia um usuário relatou que o cálculo do 'Total' estava mostrando NaN (Not a Number). Após horas de debugging, ela descobriu que para um produto específico e raro, a API estava retornando o preço como uma string: "19.99". Em JavaScript, 10 + "19.99" resulta na string "1019.99", o que quebrou seus cálculos mais para frente.

Com o TypeScript, ela poderia ter pego isso na origem. Ao validar os dados recebidos da API contra sua interface Product, a incompatibilidade de tipo teria lançado um erro no momento em que os dados ruins entrassem em seu sistema, não dez passos depois quando tentasse fazer uma conta.

Lição: O TypeScript impõe contratos de dados, tornando sua aplicação resiliente a mudanças inesperadas ou erros de APIs externas.

Erros e armadilhas comuns

  • A válvula de escape do any: O TypeScript tem um tipo especial chamado any, que basicamente diz ao compilador "confia em mim, eu sei o que estou fazendo" e desliga toda a verificação de tipos para aquela variável. Usar any em excesso é como comprar um carro por seus recursos de segurança e depois desligar todos eles. Isso anula todo o propósito de usar o TypeScript.
  • Ignorar os erros do compilador: Às vezes, você verá uma linha vermelha ondulada do TypeScript, mas o JavaScript transpilado parece rodar bem. É tentador ignorar o erro. Isso é uma armadilha. O erro é um sinal de alerta de um potencial bug em tempo de execução. Dê ouvidos ao seu compilador; ele está tentando te ajudar.
  • Lutar contra o sistema de tipos: Os novatos muitas vezes ficam frustrados quando o TypeScript não os deixa fazer algo. Em vez de descobrir a maneira correta de tipar seu código, eles tentam enganar o compilador com asserções de tipo (as any) ou outras gambiarras. Isso geralmente significa que o entendimento deles sobre o fluxo de dados está falho, e o compilador está identificando corretamente um problema.
  • Esquecer os pacotes @types: Muitas bibliotecas populares de JavaScript não incluem suas próprias definições de tipo. A comunidade TypeScript mantém um repositório gigantesco dessas definições chamado DefinitelyTyped. Se você está usando uma biblioteca como Lodash ou Express, muitas vezes precisa instalar o pacote @types/lodash correspondente para obter o autocompletion e a verificação de tipos adequados.

Por que isso deve estar no seu radar

Você deve usar o TypeScript (ou pelo menos considerá-lo) quando:

  • Seu projeto JavaScript tem mais do que um punhado de arquivos.
  • Você está trabalhando em equipe e precisa garantir que todos estejam na mesma página sobre as estruturas de dados.
  • Você se pega gastando mais tempo debugando erros de undefined do que escrevendo novas features.
  • Você quer que seu editor de código se torne um assistente superpoderoso, fornecendo autocompletion incrível, ferramentas de refatoração e mensagens de erro inline.
  • Você está construindo uma aplicação que precisa ser mantida e escalada por um longo período de tempo.

Resumindo, o TypeScript é o padrão profissional para o desenvolvimento JavaScript moderno. Aprender é um investimento que se paga com menos bugs, colaboração mais fácil e uma experiência de desenvolvimento com mais confiança.

Para ir mais fundo

Como um editor entende código

As cores vêm de um analisador da linguagem, não da execução do programa. CodeMirror e Lezer reconhecem símbolos e estrutura no navegador. As sugestões combinam palavras-chave, nomes locais quando disponíveis, trechos e uma pequena referência integrada; passar sobre um símbolo documentado revela sua assinatura. Uma sugestão não garante que a API exista no runtime. Os diagnósticos detectam sintaxe malformada quando há suporte, mas não substituem verificação de tipos nem execução: código sintaticamente válido também pode falhar. Ruby e Lua usam modos baseados em tokens, com diagnósticos mais limitados. Não há servidor remoto de linguagem; o código não precisa sair do dispositivo.

CodeMirror & Lezer: MIT.

Teoria feita. Hora de pôr a mão na massa — 100% no seu navegador.

Testar a ferramenta: Playground TypeScript