Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
LiçãoIniciantecódigo testado

Tipos de dados em JavaScript e o operador typeof

Os sete primitivos e o object, o que typeof responde em cada um e por que typeof null devolve "object" desde 1995 — com o erro que isso provoca.

Rodolfo Mori6 min de leitura

JavaScript tem oito tipos: sete primitivos — string, number, boolean, undefined, null, symbol e bigint — e o object, que abriga tudo o mais. Array não é um tipo separado. Função também não. Os dois são objetos.

O operador que responde qual é o tipo de um valor é o typeof. Ele é útil, é rápido de digitar e tem duas respostas que confundem todo mundo na primeira vez: typeof null é 'object' e typeof [] também. Esta lição mostra os oito tipos rodando e explica exatamente onde o typeof ajuda e onde ele atrapalha.

O nome é a etiqueta; o tipo pertence ao que está dentro

Imagine potes etiquetados numa cozinha. A etiqueta total ajuda você a achar o pote, mas quem decide o que pode ser feito é o conteúdo: açúcar pode entrar numa conta; uma lista de compras precisa ser percorrida. Em JavaScript, a variável é o nome e o tipo pertence ao valor guardado nela. Por isso o mesmo nome pode apontar para um número agora e para uma string depois.

typeof é uma inspeção rápida daquilo que está no pote, não um detector perfeito. Ele distingue primitivos muito bem, mas chama arrays, datas e null de object por razões que veremos. Faça um teste antes da lista completa: escreva três valores que você usa todo dia — um preço, um nome e um carrinho — e preveja o typeof de cada um. Quando chegar ao array, não confunda a prateleira “objetos” com o recipiente específico; para esse detalhe existe Array.isArray.

Os oito tipos, um por linha

js
const nome = 'Teclado mecânico';
const preco = 289.9;
const disponivel = true;
const desconto = null;
let cupom;
const etiqueta = Symbol('pedido');
const unidadesVendidas = 9007199254740993n;
const cliente = { nome: 'Ana' };

console.log(typeof nome, typeof preco, typeof disponivel);
console.log(typeof desconto, typeof cupom, typeof etiqueta);
console.log(typeof unidadesVendidas, typeof cliente);
string number boolean object undefined symbol bigint object

Vale reparar em três coisas dessa saída.

preco é number e disponivel é boolean, sem surpresa — mas note que JavaScript não tem tipo inteiro. 1 e 1.0 são o mesmo number, guardado em ponto flutuante de 64 bits. É por isso que 0.1 + 0.2 não dá exatamente 0.3, e é por isso que existe o bigint: quando o número passa de 9.007.199.254.740.991, o number comum começa a perder precisão, e o sufixo n resolve.

cupom foi declarado sem valor e vale undefined. desconto recebeu null de propósito — e apareceu como object, que é o assunto de uma seção inteira mais abaixo.

O symbol é o único que você provavelmente não vai criar nos primeiros meses. Ele existe para gerar uma chave de propriedade que ninguém colide por acidente, e aparece em código de biblioteca.

typeof responde bem, menos quando é objeto

js
console.log(typeof console.log);
console.log(typeof [289.9, 149.9]);
console.log(Array.isArray([289.9, 149.9]));
console.log(typeof new Date('2026-08-21'));
function object true object

Função devolve 'function', que nem é um dos oito tipos — é uma gentileza do operador, porque saber se algo é chamável é pergunta frequente. Fora isso, tudo que não é primitivo devolve 'object': array, data, expressão regular, objeto comum. typeof não distingue nenhum deles.

Para array existe Array.isArray, que é a resposta certa e definitiva. Para o resto, tem a técnica do fim desta lição.

Primitivo é copiado; objeto é compartilhado

Esta é a diferença que muda o comportamento do seu programa, mais do que o nome do tipo:

js
let precoA = 289.9;
let precoB = precoA;
precoB = 199;

const carrinhoA = { itens: 1 };
const carrinhoB = carrinhoA;
carrinhoB.itens = 5;

console.log(precoA, precoB);
console.log(carrinhoA.itens, carrinhoB.itens);
289.9 199 5 5

Com número, precoB = precoA copiou o valor: mexer em um não toca no outro. Com objeto, carrinhoB = carrinhoA copiou a referência — os dois nomes apontam para o mesmo objeto na memória, e alterar por um lado altera pelo outro.

Não é pegadinha: é o que permite passar um objeto grande para uma função sem duplicar a memória inteira. Mas é a origem do bug clássico de “mexi numa lista e a outra mudou junto”. Quando você quiser mesmo uma cópia independente, use structuredClone(objeto) ou o spread { ...objeto } para o primeiro nível.

typeof null devolve “object” — um bug de 1995

js
const desconto = null;

console.log(typeof desconto);
console.log(desconto === null);
console.log(desconto instanceof Object);
object true false

null não é objeto: instanceof Object diz que não, e a especificação lista null entre os primitivos. O 'object' vem da primeira implementação da linguagem, em que cada valor carregava uma etiqueta de tipo nos bits mais baixos e a etiqueta 000 significava “objeto”. O ponteiro nulo era todo zeros — e caiu na mesma etiqueta.

Já houve proposta de corrigir. Foi rejeitada porque quebraria páginas antigas em funcionamento, e a compatibilidade retroativa é o compromisso mais duro do JavaScript. Hoje o comportamento é lei escrita na especificação.

O erro que esse bug provoca

Não é curiosidade acadêmica. Quem confia no typeof para decidir se pode acessar uma propriedade escreve exatamente isto:

js
const pedido = { id: 4821, cupom: null };

if (typeof pedido.cupom === 'object') {
  console.log('código do cupom:', pedido.cupom.codigo);
}
file:///private/tmp/loja/l5-cupom.mjs:4 console.log('código do cupom:', pedido.cupom.codigo); ^

TypeError: Cannot read properties of null (reading ‘codigo’) at file:///private/tmp/loja/l5-cupom.mjs:4:48 Node.js v24.16.0

O if passou porque typeof null é 'object', e a linha de dentro quebrou porque null não tem propriedade nenhuma. A checagem honesta é if (pedido.cupom) ou pedido.cupom?.codigo. Essa família de erro — a mais comum da linguagem inteira — tem página própria: TypeError: Cannot read properties of undefined.

typeof é o único operador que não quebra em nome inexistente

js
console.log(typeof configuracaoDaLoja);

console.log(configuracaoDaLoja);
undefined file:///private/tmp/loja/l5-typeof-livre.mjs:3 console.log(configuracaoDaLoja); ^

ReferenceError: configuracaoDaLoja is not defined at file:///private/tmp/loja/l5-typeof-livre.mjs:3:13 Node.js v24.16.0

A primeira linha imprimiu undefined sem reclamar de um nome que nunca foi declarado. A segunda, com o mesmo nome, derrubou o programa. typeof é a única operação que tolera identificador inexistente — foi feita assim para permitir detectar recurso de ambiente antes de usá-lo.

Na prática moderna, o teste virou typeof window !== 'undefined' em código que roda tanto no navegador quanto no servidor. Fora esse caso, typeof em nome que pode não existir é sinal de que falta um import.

String tem método sem ser objeto

Se 'Teclado' é primitivo, como ele tem .toUpperCase()? Porque, no instante do acesso, o motor embrulha o primitivo num objeto temporário, lê a propriedade e joga o embrulho fora. Isso chama boxing, e o descarte é visível:

js
const nome = 'teclado mecânico';

console.log(nome.toUpperCase());
console.log(nome.length);

nome.marca = 'Club';
TECLADO MECÂNICO 16 file:///private/tmp/loja/l5-boxing.mjs:6 nome.marca = 'Club'; ^

TypeError: Cannot create property ‘marca’ on string ‘teclado mecânico’ at file:///private/tmp/loja/l5-boxing.mjs:6:12 Node.js v24.16.0

Ler funcionou; escrever não. Em modo estrito — o padrão em módulos — a tentativa lança. Em script antigo, sem modo estrito, ela falha calada: a propriedade some no embrulho descartado e nome.marca volta undefined na linha seguinte.

Erros comuns

Além do typeof null, dois tropeços que aparecem toda semana:

  • Usar typeof para achar array. typeof lista === 'object' também é verdadeiro para null, para {} e para uma data. Array.isArray(lista) é a pergunta certa.
  • Achar que NaN é outro tipo. Não é: NaN é number, o que faz todo sentido quando você lembra que ele nasce de uma conta numérica que deu errado.
js
console.log(typeof NaN);
console.log(typeof (289.9 * 'dois'));
console.log(typeof Infinity);
number number number

NaN e as três formas de vazio da linguagem têm lição própria em null, undefined e NaN, que é a próxima da trilha.

Como checar tipo de verdade

Quando typeof não basta, existe um truque que devolve o nome interno do tipo, o mesmo que a especificação usa:

js
const tipoReal = (valor) => Object.prototype.toString.call(valor).slice(8, -1);

console.log(tipoReal(null));
console.log(tipoReal(undefined));
console.log(tipoReal([289.9]));
console.log(tipoReal(new Date('2026-08-21')));
console.log(tipoReal(289.9));
Null Undefined Array Date Number

Na rotina do dia a dia, porém, a ordem é mais simples do que parece:

o que você quer saber use
é texto, número ou booleano typeof valor === 'string'
é null valor === null
é array Array.isArray(valor)
é chamável typeof valor === 'function'
tem valor útil valor != null

Guardar essa tabela poupa mais tempo do que decorar os oito tipos. E se você chegou aqui vindo da lição de variáveis em JavaScript, a conexão é direta: o nome não tem tipo, o valor tem — e é por isso que conferir o valor com console.log antes de usá-lo continua sendo o hábito mais barato da programação.

Prefere aprender em vídeo?

Tem uma aula sobre este assunto no nosso canal.

Ver todos os vídeos do canal
  • javascript
  • tipos
  • typeof
  • primitivos
  • objetos

Perguntas frequentes

Quantos tipos existem em JavaScript?
Sete primitivos — string, number, boolean, undefined, null, symbol e bigint — mais o object, que abriga array, função, data e tudo que não é primitivo. Array e função não são tipos separados; são objetos.
Por que typeof null devolve object?
É um defeito da primeira implementação, de 1995, em que valores eram etiquetados por bits e null compartilhava a etiqueta de objeto. Corrigir quebraria páginas antigas, então a especificação congelou o comportamento.
Como sei se uma variável é um array?
Com Array.isArray, nunca com typeof — que devolve "object" para array, data, null e objeto comum sem distinguir nenhum deles. Para os demais casos, Object.prototype.toString.call devolve o nome interno do tipo.
Qual a diferença entre valor primitivo e objeto na prática?
Primitivo é copiado na atribuição; objeto é compartilhado por referência. Dois nomes apontando para o mesmo objeto enxergam a mesma alteração, e é daí que vem o bug de alterar uma lista e ver a outra mudar junto.

Dúvidas e comentários

Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.

Todo o código deste artigo foi executado em Node 24.16.0, e as saídas exibidas são as reais — como produzimos este conteúdo.

Fontes consultadas

  1. MDN — Tipos de dados e estruturas em JavaScript — developer.mozilla.org
  2. ECMAScript — The typeof Operator — tc39.es

Continue por aqui