Dois tipos de coerção
O JavaScript é flexível com tipos. Quando um operador recebe um valor do tipo "errado", a linguagem não dispara erro — ela converte. Essa conversão se chama coerção, e ela aparece de duas formas:
- Explícita — quando você pede:
Number("42"),String(99),Boolean(value). - Implícita — quando um operador dispara a conversão sem você escrever nada:
"5" - 2,"" == 0,if (value).
As duas acabam chamando as mesmas regras de conversão por baixo dos panos. A diferença é quem decidiu converter: você ou a linguagem. Quase todo resultado confuso do JavaScript — "5" + 1 === "51", [] == false, null == undefined — vem de uma coerção implícita que te pega desprevenido.
O modelo mental é simples: se você escreve Number(...) ou String(...), você sabe exatamente o que está pedindo. Quando não escreve, cada operador tem a sua própria opinião sobre o que fazer — e é justamente aí que os bugs se escondem.
Os três tipos de destino na coerção
A coerção de tipos em JavaScript sempre converte para um de três tipos primitivos: string, number ou boolean. (Existe um quarto, o bigint, mas ele nunca recebe coerção automática a partir de outros tipos.) Todo o resto das regras decorre de qual desses alvos o operador está mirando.
A coerção para string é a mais camarada — todo valor tem uma forma em string. Repare que objetos viram aquele "[object Object]" que não ajuda em nada, e é por isso que dar log em um objeto concatenado com string ("user: " + user) quase nunca mostra o que você queria ver. Nesses casos, prefira JSON.stringify ou template literals com os campos específicos.
Coerção para Number
Já a coerção para número é mais rígida. A string precisa realmente ter cara de número, senão você recebe NaN:
As surpresas entre parênteses são justamente as que vale a pena decorar:
- String vazia e strings só com espaços viram
0, e nãoNaN. nullvira0, masundefinedviraNaN.- Array vazio vira
0; array com um único elemento força a coerção desse elemento; array com vários elementos viraNaN.
Quando você precisa extrair um número de uma string que tem caracteres extras, use parseInt ou parseFloat no lugar de Number:
Sempre passe a base (10) para o parseInt. Sem ela, strings que começam com "0x" são interpretadas como hexadecimal, o que quase nunca é o que você quer.
Coerção para Boolean
A coerção para booleano é a mais simples das três. Existe uma pequena lista de valores que viram false — todo o resto vira true.
Os valores falsy são:
false0,-0,0n""(string vazia)nullundefinedNaN
É isso. Qualquer outro valor — incluindo "false", "0", [] e {} — é truthy.
Os resultados de array vazio e objeto vazio costumam pegar de surpresa quem vem do Python, onde coleções vazias são falsy. No JavaScript, elas são truthy — se você quer saber "esse array está vazio?", verifique explicitamente com arr.length === 0.
A coerção para booleano acontece sempre que um valor aparece onde se espera um booleano: if (...), while (...), o ternário ? : e os operadores lógicos &&, ||, !.
O operador + é um caso à parte
A maioria dos operadores aritméticos força seus operandos para número. Já o + é diferente: se qualquer um dos lados for uma string, o + faz concatenação de strings. Caso contrário, faz soma numérica.
A avaliação acontece da esquerda para a direita. Em 1 + 2 + "3", primeiro o JS calcula 1 + 2 = 3 e depois 3 + "3" = "33". Já "1" + 2 + 3 começa como string e segue como string até o fim: vira "12" e depois "123".
É por isso que montar strings com + é furada. Com template literals, esse problema some:
O template literal avalia count + 1 como uma expressão numérica isolada e só depois interpola o resultado. Sem coerção inesperada no caminho.
Prefira conversões explícitas
Quando você precisa converter um tipo, deixe isso claro no código. Custa alguns caracteres a mais e elimina qualquer ambiguidade para quem for ler depois:
A mesma ideia vale para booleanos. O !!value funciona e é bem comum, mas o Boolean(value) deixa explícito o que está acontecendo:
Uma regra razoável: use conversões explícitas na lógica da sua aplicação e reserve as formas curtas (+x, !!x) para situações em que a concisão importa e a intenção já fica clara pelo contexto.
O operador == depende muito da coerção
Os operadores de igualdade são a maior fonte de surpresas envolvendo coerção de tipos em JavaScript. O == faz coerção antes de comparar; o === não.
Cada true do exemplo acima é o resultado de uma cadeia de coerção de vários passos que a maioria dos devs não consegue recitar de cabeça. E aí está o problema — código que funciona por acidente é código que vai quebrar mais tarde. Vamos mergulhar nas regras completas de igualdade na próxima página; por enquanto, fica a dica: use === por padrão, e só recorra ao == para o idioma específico x == null (que pega tanto null quanto undefined).
Juntando tudo na prática
Um exemplo trabalhado mostrando onde a coerção ajuda e onde ela atrapalha:
Repare na segunda chamada. Number("") devolve 0, e não NaN — então parsePrice("") acaba retornando 0, o que provavelmente não é o que quem usa essa função espera. Se a ideia é rejeitar entrada vazia, adicione uma verificação explícita:
Saber quais valores viram 0 e quais viram NaN é exatamente o tipo de detalhe que evita um bug chato lá na frente.
O que levar dessa aula
- A coerção de tipos em JavaScript converte valores para string, número ou booleano dependendo do operador.
+com qualquer string vira concatenação; todos os outros operadores aritméticos convertem para número.- Os valores falsy são uma lista curta e fixa — decore. Todo o resto é truthy, inclusive
[]e{}. Number("")é0,Number([])é0,Number(null)é0— masNumber(undefined)éNaN. Isso aparece em bugs reais.- Prefira
Number(x),String(x)eBoolean(x)no lugar de truques implícitos espertinhos. Seu eu do futuro agradece.
A seguir: operadores de igualdade
Tudo que a coerção faz nas comparações mora dentro do ==. Na próxima página a gente compara ==, === e Object.is, vê o único caso em que o == ainda é útil, e por que os linters já marcam a forma frouxa por padrão.
Perguntas frequentes
O que é coerção de tipos em JavaScript?
Coerção de tipos é quando o JavaScript converte automaticamente um valor de um tipo para outro — um número virando string, uma string virando número, ou qualquer coisa virando boolean. Isso acontece de forma implícita quando operadores como +, == ou if recebem um valor que não é do tipo esperado, e de forma explícita quando você mesmo chama Number(x), String(x) ou Boolean(x).
Qual a diferença entre coerção implícita e explícita?
A coerção explícita é quando você chama uma função de conversão de propósito: Number("42"), String(99), Boolean(valor). Já a implícita é quando o próprio operador dispara a conversão pelas suas costas: "5" - 2 devolve 3, mas "5" + 2 devolve "52". A explícita é legível e previsível; a implícita é a origem da maioria dos bugs do tipo "por que isso virou NaN?".
Como converter string para número em JavaScript?
Use Number("42") para uma conversão estrita (retorna NaN se a string não for um número válido), ou parseInt("42px", 10) / parseFloat("3.14em") quando você quer extrair o número do começo de uma string mais bagunçada. O operador unário + (+"42") faz o mesmo que Number(), mas passa despercebido quando você bate o olho rápido no código.
Por que [] + [] retorna uma string vazia?
[] + [] retorna uma string vazia?O operador + não tem uma operação numérica que faça sentido entre dois arrays, então o JavaScript converte os dois para string. Arrays viram string juntando os elementos com vírgula, e um array vazio vira "". Ou seja, [] + [] acaba como "" + "", que dá "". É uma curiosidade divertida — e um ótimo argumento para nunca usar + com valores que não são primitivos.