Como Usar Tipos de Dados em JavaScript: Primitivos, Objetos e Coerção de Tipos em Produção Já leu

Tipos Primitivos: A Base de Tudo Em JavaScript, existem sete tipos primitivos: , , , , , e . Eles são imutáveis e armazenados diretamente na memória, o que os torna eficientes para operações básicas. Quando você trabalha em produção, entender como esses tipos se comportam é crucial para evitar bugs sutis. Um erro comum em produção é confundir com . Use quando você intencionalmente quer representar ausência, e aparece quando uma variável não foi atribuída ou uma função não retorna nada. Para verificar com segurança se algo é nulo, prefira ou use o operador nullish coalescing ( ). Objetos e Referências: Comportamento em Memória Diferente dos primitivos, objetos são tipos de referência. Eles ocupam mais memória e são armazenados como referências, não valores diretos. Em aplicações grandes, isso afeta performance e pode gerar comportamentos inesperados se não for bem compreendido. Em produção, essa diferença causa problemas reais. Se você passa um objeto para uma função e a função o

Tipos Primitivos: A Base de Tudo

Em JavaScript, existem sete tipos primitivos: string, number, boolean, null, undefined, symbol e bigint. Eles são imutáveis e armazenados diretamente na memória, o que os torna eficientes para operações básicas. Quando você trabalha em produção, entender como esses tipos se comportam é crucial para evitar bugs sutis.

// Exemplos de tipos primitivos
const nome = "João";              // string
const idade = 30;                 // number
const ativo = true;               // boolean
const vazio = null;               // null (ausência intencional)
const naoDefinido = undefined;    // undefined (não foi atribuído)
const id = Symbol('user');        // symbol (único e imutável)
const grandeNumero = 900719925474099n; // bigint

// Verificar tipos com typeof
console.log(typeof nome);         // "string"
console.log(typeof idade);        // "number"
console.log(typeof ativo);        // "boolean"
console.log(typeof null);         // "object" (bug histórico do JS!)
console.log(typeof naoDefinido);  // "undefined"

Um erro comum em produção é confundir null com undefined. Use null quando você intencionalmente quer representar ausência, e undefined aparece quando uma variável não foi atribuída ou uma função não retorna nada. Para verificar com segurança se algo é nulo, prefira valor === null || valor === undefined ou use o operador nullish coalescing (??).

Objetos e Referências: Comportamento em Memória

Diferente dos primitivos, objetos são tipos de referência. Eles ocupam mais memória e são armazenados como referências, não valores diretos. Em aplicações grandes, isso afeta performance e pode gerar comportamentos inesperados se não for bem compreendido.

// Primitivo: cópia por valor
let a = 10;
let b = a;
b = 20;
console.log(a); // 10 (não foi afetado)

// Objeto: cópia por referência
const usuario1 = { nome: "Ana", idade: 28 };
const usuario2 = usuario1;
usuario2.idade = 29;
console.log(usuario1.idade); // 29 (ambos apontam para o mesmo objeto!)

// Para copiar objetos com segurança, use spread operator
const usuario3 = { ...usuario1 };
usuario3.idade = 25;
console.log(usuario1.idade); // 29 (agora sim, são independentes)

// Arrays também são objetos
const numeros = [1, 2, 3];
const copia = [...numeros]; // cópia segura
copia[0] = 999;
console.log(numeros[0]); // 1 (seguro)

Em produção, essa diferença causa problemas reais. Se você passa um objeto para uma função e a função o modifica, o original também muda. Para evitar isso, sempre faça cópias profundas quando necessário: use JSON.parse(JSON.stringify(obj)) para casos simples ou bibliotecas como lodash.clonedeep() para estruturas complexas.

Coerção de Tipos: O Perigo Invisível

A coerção de tipos é quando JavaScript converte automaticamente um tipo em outro. É poderosa, mas perigosa em produção se não for controlada. O JavaScript faz isso em comparações (==), operações aritméticas e contextos lógicos.

// Comparação solta (==) causa coerção
console.log(0 == false);        // true (ambos são "falsy")
console.log("5" == 5);          // true (string convertida para number)
console.log(null == undefined); // true (coerção estranha!)

// Comparação estrita (===) NÃO causa coerção
console.log(0 === false);        // false
console.log("5" === 5);          // false
console.log(null === undefined); // false

// Operações aritméticas forçam coerção
console.log("10" - "5");         // 5 (strings convertidas)
console.log("10" + 5);           // "105" (concatenação, não soma!)
console.log(true + 1);           // 2 (true vira 1)

// Valores "falsy" em JavaScript
const falsy = [false, 0, "", null, undefined, NaN];
falsy.forEach(val => {
  if (!val) console.log(`${val} é falsy`);
});

// Conversão explícita é melhor para produção
const entrada = "42";
const numero = Number(entrada);        // 42
const string = String(100);            // "100"
const booleano = Boolean("texto");     // true

Boas Práticas com Coerção

Sempre use === em vez de == — essa é a regra de ouro. Ferramentas como ESLint forçam isso automaticamente. Converta tipos explicitamente quando necessário e documente a razão. Isso torna o código mais seguro e facilita manutenção futura por outros desenvolvedores.

Tipos em Produção: Aplicação Prática

Um exemplo real: ao processar dados de uma API, você recebe strings que precisam virar números. Se usar == para comparar, pode levar horas debugando comportamentos estranhos.

// Simulando dados de uma API
const dados = {
  id: "123",
  preco: "99.99",
  em_estoque: "true"
};

// ❌ Errado em produção
if (dados.em_estoque == true) {
  console.log("Disponível");
}

// ✅ Certo
const preco = parseFloat(dados.preco);
const emEstoque = dados.em_estoque === "true";

if (emEstoque && preco > 50) {
  console.log(`Produto caro: R$ ${preco.toFixed(2)}`);
}

// Validação de tipos com guard clauses
function processocriarPedido(usuario, itens) {
  if (typeof usuario !== "object" || usuario === null) {
    throw new Error("Usuário deve ser um objeto válido");
  }
  if (!Array.isArray(itens) || itens.length === 0) {
    throw new Error("Itens deve ser um array não-vazio");
  }
  // Continua a lógica...
  return { sucesso: true };
}

console.log(processocriarPedido({ id: 1 }, [{ id: 1, qtd: 2 }]));

Conclusão

Os tipos em JavaScript definem como seu código se comporta em produção. Primeiro, domine os sete tipos primitivos e quando usar null versus undefined. Segundo, entenda que objetos são referências, não cópias, e implemente cópias seguras quando necessário. Terceiro, evite coerção implícita usando === e conversões explícitas — isso previne bugs sutis que custam caro em produção. Aplique estas práticas desde o início e seu código será mais confiável e manutenível.

Referências


Artigos relacionados