Coerção de tipos e comparação com == e ===
1. O que é coerção de tipos?
Coerção de tipos é o processo automático ou manual de converter um valor de um tipo para outro em JavaScript. Existem duas formas principais:
- Coerção implícita: O JavaScript converte automaticamente os tipos durante operações. Exemplo:
"5" - 3resulta em2(string vira número). - Coerção explícita: O desenvolvedor intencionalmente converte usando funções como
Number(),String()ouBoolean().
O JavaScript possui 7 tipos primitivos: string, number, boolean, null, undefined, symbol e bigint. Objetos (arrays, funções, datas) são tipos complexos. A coerção segue regras previsíveis, mas muitas vezes contra-intuitivas, sendo fonte clássica de bugs — especialmente quando combinada com o operador ==.
console.log(1 + "2"); // "12" (coerção implícita)
console.log(Number("42")); // 42 (coerção explícita)
console.log(!!"texto"); // true (coerção explícita via !!
2. O operador == (igualdade abstrata)
O operador == aplica coerção automática antes da comparação, seguindo regras da especificação ECMAScript (Seção 7.2.14). As principais regras são:
- Se os tipos são iguais, compara diretamente (como
===). - Se um é
nulle outroundefined, retornatrue. - Se um é número e outro string, converte string para número.
- Se um é booleano, converte para número (
true→ 1,false→ 0). - Se um é objeto e outro primitivo, chama
ToPrimitive()no objeto.
console.log(0 == false); // true (false → 0)
console.log("" == 0); // true ("" → 0)
console.log(null == undefined); // true (regra especial)
console.log("1" == true); // true (true → 1, "1" → 1)
3. O operador === (igualdade estrita)
O === compara valor e tipo sem realizar coerção. É sempre mais previsível e recomendado na maioria dos casos.
console.log(0 === false); // false (tipos diferentes)
console.log("" === 0); // false
console.log(null === undefined); // false
No Node.js, === é especialmente importante para evitar bugs em validações de dados. Porém, existem casos onde === ainda surpreende:
console.log(NaN === NaN); // false (NaN nunca é igual a nada)
console.log(-0 === +0); // true (mas são diferentes em Object.is)
console.log(Object.is(NaN, NaN)); // true
4. Casos polêmicos e pegadinhas comuns
Alguns exemplos clássicos que mostram o comportamento bizarro do ==:
console.log([] == ![]); // true (![] é false, [] → "" → 0, false → 0)
console.log([] == 0); // true ([] → "" → 0)
console.log([1] == 1); // true ([1] → "1" → 1)
console.log("1" == true); // true ("1" → 1, true → 1)
Comparação de objetos sempre compara referência, não valor:
console.log({} == {}); // false (referências diferentes)
console.log([] == []); // false
const a = [1]; const b = a;
console.log(a == b); // true (mesma referência)
null e undefined são iguais com ==, mas diferentes com ===:
console.log(null == undefined); // true
console.log(null === undefined); // false
5. Coerção em operadores lógicos e condicionais
Operadores como if, && e || usam o conceito de truthy e falsy. Valores falsy em JavaScript:
false0(e-0)""(string vazia)nullundefinedNaN
Todos os outros são truthy.
if ("") console.log("nunca executa"); // falsy
if ("texto") console.log("executa"); // truthy
if (0) console.log("nunca executa"); // falsy
if ([]) console.log("executa"); // array vazio é truthy!
Armadilha comum: confundir 0 com false ou "" com false:
const valor = 0;
if (valor == false) console.log("cuidado!"); // true com ==
if (valor === false) console.log("seguro"); // false com ===
6. Boas práticas para React e Node.js
No desenvolvimento com React e Node.js, o ESLint com a regra eqeqeq (ativada por padrão) proíbe o uso de ==, exceto em casos explícitos.
React — Comparação em hooks:
// Ruim: dependência pode causar re-renderizações inesperadas
useEffect(() => {
fetchData();
}, [props.user == null]); // comportamento imprevisível
// Bom: use === ou expressões claras
useEffect(() => {
fetchData();
}, [props.user === null]);
Node.js — Quando == null é seguro:
// Seguro: verifica null e undefined ao mesmo tempo
function processData(data) {
if (data == null) {
throw new Error('Dados inválidos');
}
// processa data...
}
// Equivalente com ===
if (data === null || data === undefined) {
// ...
}
7. Coerção explícita: como controlar a conversão
Para evitar surpresas, converta tipos explicitamente:
// Para string
String(123); // "123"
(123).toString(); // "123"
`${123}`; // "123" (template literal)
// Para número
Number("42"); // 42
parseInt("42px", 10); // 42
parseFloat("3.14"); // 3.14
// Para booleano
Boolean(1); // true
!!"texto"; // true
!!0; // false
Diferença entre toString() e String():
const obj = { toString: () => "custom" };
console.log(String(obj)); // "custom"
console.log(obj.toString()); // "custom"
// Mas String() também funciona com null/undefined
console.log(String(null)); // "null"
// null.toString() lançaria TypeError
8. Testes e debugging de comparações
Use console.log e typeof para investigar coerção:
const valor = "5";
console.log(typeof valor); // "string"
console.log(valor + 3); // "53" (concatenação)
console.log(valor - 3); // 2 (coerção numérica)
console.log(typeof (valor - 3)); // "number"
No Node.js REPL, teste interativamente:
$ node
> 0 == false
true
> [] == ![]
true
> typeof NaN
'number'
Em testes unitários (ex: Jest), seja explícito:
test('comparação segura', () => {
expect(Number("42")).toBe(42);
expect("42" === 42).toBe(false);
expect(null == undefined).toBe(true); // se intencional
});
Referências
- MDN Web Docs: Comparação de igualdade — Documentação oficial sobre
==,===eObject.is(). - ECMAScript Specification: Abstract Equality Comparison — Especificação técnica completa do operador
==. - JavaScript.info: Type Conversions — Tutorial detalhado sobre coerção explícita e implícita.
- ESLint: eqeqeq rule — Documentação da regra que recomenda
===sobre==. - You Don't Know JS: Types & Grammar — Livro online de Kyle Simpson, referência sobre coerção e tipos em JavaScript.
- React Docs: useEffect — Documentação oficial sobre efeitos e comparação de dependências.
- Node.js Docs: Assert — Módulo nativo para testes, útil para verificar igualdade estrita.