Você já sentiu aquela pontada de dúvida ao receber um retorno de uma API ou ao lidar com uma biblioteca externa?
Nessas horas, o any parece um abraço quentinho: ele aceita tudo, não reclama de nada e deixa o código rodar. Mas, como diz o ditado no mundo dev, “com grandes poderes vêm grandes responsabilidades” (e, às vezes, grandes erros de ).
Autor(a)
mikedesousa80
Inscreva-se em nossa Newsletter
Fique por dentro de conteúdos, insights e oportunidades do universo tech. Receba novidades e lançamentos direto no seu e-mail.
runtime
Podemos pensar no any e no unknown como dois guias em uma floresta desconhecida. O any é aquele guia excessivamente otimista que diz: “Pode pisar em qualquer lugar, está tudo bem!”, até que você pisa em um buraco.
Já o unknown é o guia cauteloso: ele para você na frente de cada arbusto e diz: “Não dê um passo até verificarmos se o chão é firme.”
Manter a tipagem segura não é apenas um “capricho” técnico. No mercado atual, onde sistemas escaláveis e colaboração entre grandes times são a regra, a clareza do código é o que separa um projeto de sucesso de um pesadelo de manutenção.
O unknown é o “irmão responsável” do any, e ele permite que você mantenha a flexibilidade de dados dinâmicos sem abrir mão da proteção que o TypeScript oferece.
O que é o tipo any?
O any é, essencialmente, a “porta de saída” do sistema de tipos do TypeScript. Quando você atribui any a uma variável, você está dizendo ao compilador: “Ei, confie em mim, eu sei o que estou fazendo. Não precisa validar nada aqui”.
É o tipo mais flexível da linguagem, pois ele representa literalmente qualquer valor e permite que você acesse qualquer propriedade ou método sem questionamentos.
Na prática, o any costuma aparecer em três cenários principais:
Migração de JavaScript para TypeScript: Quando o volume de erros é tão grande que o “tipar tudo com any” parece a única saída para fazer o código compilar.
Pressa no desenvolvimento: Aquele famoso “depois eu arrumo” que acaba ficando para sempre no repositório.
Dados de origens incertas: Quando a pessoa desenvolvedora não tem certeza da estrutura que virá de um JSON externo.
O grande risco aqui é o efeito cascata. Se uma função retorna any, qualquer variável que receba esse valor também perde a proteção de tipo. Em pouco tempo, você terá um código TypeScript que se comporta como JavaScript puro, onde erros como TypeError: ‘x’ is not a function assombram as suas noites.
Da uma olhada nesse exemplo propositalmente absurdo:
O TypeScript não acusa erro. Mas em tempo de execução, o código quebra. Por quê? Porque a variável listaDeExemplo no momento do push já não é mais um number[]. É uma string. Ou seja: o any permitiu que eu mentisse para o sistema de tipos, e ele acreditou.
E o resultado? Bem...
É exatamente o tipo de problema que o TypeScript existe para evitar. No fim das contas, any não é apenas “um tipo flexível”, ele é a desativação do TypeScript naquele ponto do código.
O que é o tipo unknown?
O unknown é o que chamamos de tipo universal seguro. Assim como o any, você pode atribuir qualquer valor a uma variável do tipo unknown. No entanto, a semelhança para por aí. A grande diferença é que o TypeScript não permite que você faça nada com um valor unknown até que você verifique o que ele é.
A regra de ouro aqui é a cautela: você sabe que algo existe ali dentro, pode ser uma string, um objeto ou um número, por exemplo, mas você não sabe o que é (ainda).
Até mesmo tentar acessar a propriedade length em um unknown resultará em um erro de compilação.
A semântica do “Eu não sei”
Usar unknown comunica uma intenção clara para outras pessoas devs: “Eu recebi esse dado de algum lugar e não posso garantir sua estrutura agora”. É uma forma honesta de programar. Em vez de fingirmos que tudo está sob controle (como o any faz), admitimos a incerteza e preparamos o terreno para uma validação segura.
Como implementar na prática?
Agora que já entendemos a teoria, vamos colocar a mão na massa. O segredo para dominar o unknown é entender o conceito de Narrowing (estreitamento, afunilamento). Basicamente, é o processo de transformar um tipo genérico e desconhecido em algo específico e utilizável.
Quando trabalhamos com unknown, o desafio não é escrever o if, o desafio é não saber o que pode chegar, e é exatamente isso que diferencia esse cenário de quando usamos unions.
Cenário A: Tipagem restrita (Unions)
Imagine que você está criando uma função que recebe dados que podem ser:
uma string
um array de strings
ou null
Aqui você já conhece todas as possibilidades. O TypeScript consegue acompanhar o seu raciocínio conforme você trata cada caso.
Nesse cenário, o narrowing acontece de forma natural.
O compilador entende:
se passou pela verificação de array, então só pode ser string[]
se passou pela verificação de string, então só pode ser string
Existe uma lista fechada de possibilidades e isso torna o código previsível e mais fácil de modelar.
Cenário B: O desafio do unknown
Agora imagine um outro caso: você recebe um dado desconhecido, pode ser o valor do localStorage, o resultado de um JSON.parse(), o retorno de uma biblioteca, um evento de usuário, etc.
Nesse momento você não tem nenhuma garantia sobre o formato desse dado.
É aí que entra o unknown.
functionprocessarDesconhecido(valor: unknown) {
if (Array.isArray(valor)) {
valor.forEach(item =>console.log(item));
}
elseif (typeof valor === "string") {
console.log(valor.trim());
}
}
Aqui o TypeScript não possui uma lista prévia de tipos possíveis, ele apenas sabe que esse valor pode ser qualquer coisa. Por isso ele exige que você investigue o dado antes de utilizá-lo.
Cada verificação funciona como uma etapa de validação:
Primeiro testamos se o valor é um array
Caso não seja, testamos se é uma string
Quando uma dessas condições é verdadeira, o tipo é estreitado dentro daquele bloco, ou seja:
antes → unknown
depois → um tipo específico e utilizável
Esse é o narrowing acontecendo na prática.
Quando o narrowing simples não é suficiente
Até agora usamos verificações básicas como o typeof e o Array.isArray, e isso funciona muito bem para tipos primitivos ou estruturas mais simples. Mas e quando estamos lidando com objetos complexos?
Nesse caso precisamos de uma forma mais estruturada de validar o tipo.
Cenário C: Recebendo dados de APIs externas
Ao consumir uma API, não temos controle total sobre o que o servidor envia (especialmente se for um serviço de terceiros). Em vez de tipar o retorno com any, use unknown.
Aqui o TypeScript impede o acesso direto às propriedades porque resultado é unknown. Isso nos força a validar antes de usar.
O uso de Type Guards
Para “desbloquear” o valor dentro de um unknown, usamos funções chamadas Type Guards. Elas verificam o tipo em tempo de execução e informam ao TypeScript que o valor é seguro.
Uma resposta típica da API ViaCEP contém campos como:
{"cep":"01001-000","logradouro":"Praça da Sé","bairro":"Sé","localidade":"São Paulo","uf":"SP"}
A interface como contrato: Criamos a interface EnderecoViaCEP para definir como esperamos que os dados sejam. É o nosso “cenário ideal”.
O parâmetro unknown: Note que na função ehEnderecoViaCEP, o dado entra como unknown. Isso é honesto: antes da validação, não podemos garantir que a API não retornou um erro ou um formato vazio.
O predicado de tipo: O segredo está no retorno dado is EnderecoViaCEP. Assim dizemos ao TypeScript: “Se esta função retornar true, você pode confiar que dado possui todas as propriedades da interface”.
A checagem de segurança: Dentro do if, o TypeScript faz o narrowing. Note que você pode digitar resultado. e o VS Code vai sugerir “logradouro” ou “localidade” com total confiança. Se o if falhar (caso a API mude o formato, por exemplo), caímos no else e evitamos que o sistema quebre tentando ler uma propriedade que não existe.
Conclusão
Chegamos ao fim da nossa jornada entre o permissivo e o seguro. Entender a diferença entre any e unknown é um divisor de águas na carreira de qualquer pessoa que desenvolve com TypeScript.
Ao escolher o unknown, você não está apenas silenciando o compilador, você está assumindo o compromisso de escrever um código mais resiliente, legível e profissional.
É uma mudança de mentalidade que transforma o "programar por tentativa e erro" em "programar com confiança", aplicando conceitos de Clean Code desde a base da sua aplicação.
Como aprender mais sobre o tema?
Essa mesma mentalidade é exatamente o que a Carreira de Desenvolvimento Front-End Reactpropõe: uma evolução estruturada que vai além de “fazer funcionar”, preparando você para construir aplicações robustas, aplicar boas práticas arquiteturais e tomar decisões técnicas com confiança.
Ao dominar tipagem, testes, performance e padrões modernos dentro do ecossistema React, você transforma conhecimento em maturidade profissional, dando passos consistentes rumo à autonomia e, no futuro, à liderança técnica.
FAQ | Perguntas frequentes sobre o tipo Unknown
1. O unknown substitui o any em 100% dos casos?
Quase todos. O any ainda tem seu lugar em testes rápidos ou prototipagem inicial. Para produção, prefira sempre o unknown.
2. Usar unknown deixa o código mais lento?
Não. O TypeScript é removido na compilação. O custo é apenas o pequeno tempo de escrever as validações de tipo, o que economiza horas de debug depois.
3. Qual a diferença entre usar unknown e fazer um Type Assertion (as)?
O unknown obriga você a provar o tipo através de lógica (como typeof ou if). Já o Type Assertion (valor as Endereco) é você “forçando a barra” e dizendo ao compilador: “Trate isso como Endereco”. O assertion é mais arriscado, pois se o dado vier errado da API, o TypeScript não vai te avisar e o erro vai estourar no console da pessoa usuária.
4. Posso usar unknown para tipas o JSON.parse()?
Sim, e essa é uma excelente prática. Por padrão, o JSON.parse() retorna any, o que é um perigo silencioso. Ao atribuir o resultado a uma variável unknown, você se força a validar o JSON antes de acessar propriedades que podem não existir, tornando o processamento de dados muito mais robusto.