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

Operador ternário em JavaScript: if em uma linha

O ternário é expressão, não instrução — por isso cabe dentro de template literal e de JSX. Aninhamento, comparação com ?? e o SyntaxError do : sozinho.

Rodolfo Mori6 min de leitura

O operador ternário escolhe entre dois valores conforme uma condição: condicao ? valorSeVerdadeiro : valorSeFalso. É o único operador da linguagem que recebe três operandos — daí o nome.

A diferença que importa não é o tamanho. O ternário é uma expressão: ele devolve um valor. O if é uma instrução: ele executa um bloco e não devolve nada. Por isso o ternário cabe dentro de um template literal, dentro de um argumento de função e dentro do JSX — três lugares onde um if simplesmente não entra.

Se você ainda não viu a versão longa da decisão, ela está em if else em JavaScript, a lição anterior.

Uma bifurcação que precisa devolver um valor

Imagine uma etiqueta de frete com um único espaço: se o pedido passou de cem reais, escreva “grátis”; caso contrário, escreva o preço. A decisão precisa terminar com um valor para ocupar aquele espaço. Esse é o cenário em que o ternário encaixa naturalmente.

Tecnicamente, o operador ternário é uma expressão condicional. Ele avalia a condição e devolve exatamente um dos dois operandos; por isso cabe numa variável, num argumento ou no JSX. No primeiro exemplo, cubra os dois valores com a mão, avalie a condição e escolha um. Depois confira se a saída mostra justamente o ramo previsto.

js
const total = 250;

const frete = total >= 199 ? 0 : 24.9;

console.log(frete);
console.log(total >= 199 ? 'Frete grátis' : 'Frete: R$ 24,90');
0 Frete grátis

Repare na segunda linha: o ternário foi direto para dentro do console.log, sem variável intermediária. Ele é um valor, e valor vai onde valor vai.

Expressão contra instrução, lado a lado

Este par mostra por que o ternário existe. Com if, você precisa declarar a variável antes, vazia, e preencher nos dois braços:

js
const total = 120;

let freteComIf;
if (total >= 199) {
  freteComIf = 0;
} else {
  freteComIf = 24.9;
}

const freteComTernario = total >= 199 ? 0 : 24.9;

console.log(freteComIf, freteComTernario);
console.log(typeof (total >= 199 ? 0 : 24.9));
24.9 24.9 number

Duas coisas mudaram além do tamanho. freteComIf teve que ser let, porque recebe valor depois — e uma variável que pode ser reatribuída é uma variável que alguém pode reatribuir. Com o ternário, freteComTernario é const: nasce com o valor final e ninguém mexe mais.

A última linha é a prova de que estamos falando de expressão: typeof só se aplica a algo que tem tipo. typeof (if ...) não é código válido.

Dentro de um template literal

Este é o uso mais comum no dia a dia, e o que o if não consegue imitar:

js
const pedido = { cliente: 'Ana', itens: 3, total: 289.9 };

console.log(
  `${pedido.cliente} tem ${pedido.itens} ${pedido.itens === 1 ? 'item' : 'itens'} ` +
    `e paga ${pedido.total >= 199 ? 'frete grátis' : 'R$ 24,90 de frete'}`,
);

const vazio = { cliente: 'Bruno', itens: 1, total: 49.9 };
console.log(
  `${vazio.cliente} tem ${vazio.itens} ${vazio.itens === 1 ? 'item' : 'itens'} ` +
    `e paga ${vazio.total >= 199 ? 'frete grátis' : 'R$ 24,90 de frete'}`,
);
Ana tem 3 itens e paga frete grátis Bruno tem 1 item e paga R$ 24,90 de frete

Dentro de ${ } só cabe expressão. Pluralizar “item/itens” com if exigiria montar a frase em pedaços, numa variável, antes da interpolação — três linhas para resolver uma letra.

Dentro do JSX

Em React vale a mesma regra: { } no JSX aceita expressão, não instrução. Por isso o ternário é onipresente em componente:

jsx
function ResumoDoPedido({ pedido }) {
  return (
    <div className="pedido">
      <h2>Pedido #{pedido.id}</h2>
      <span className={pedido.pago ? 'badge badge-ok' : 'badge badge-alerta'}>
        {pedido.pago ? 'Pago' : 'Aguardando pagamento'}
      </span>
      {pedido.itens.length > 0 ? (
        <ul>
          {pedido.itens.map((item) => (
            <li key={item.id}>{item.nome}</li>
          ))}
        </ul>
      ) : (
        <p>Carrinho vazio</p>
      )}
    </div>
  );
}

Três ternários, três funções diferentes: escolher uma classe CSS, escolher um texto e escolher entre dois blocos de marcação. Nos três casos o resultado é colocado em algum lugar — e é isso que exige expressão.

Aninhar: até onde a escada ainda lê

Ternário dentro de ternário é legítimo — o operador é associativo à direita, e o segundo : fecha a segunda pergunta. Formatado como escada, funciona bem para faixas:

js
function etiquetaDeFrete(total) {
  return total >= 199
    ? 'grátis'
    : total >= 99
      ? 'R$ 9,90'
      : total >= 49
        ? 'R$ 14,90'
        : 'R$ 24,90';
}

console.log(etiquetaDeFrete(250));
console.log(etiquetaDeFrete(120));
console.log(etiquetaDeFrete(60));
console.log(etiquetaDeFrete(30));
grátis R$ 9,90 R$ 14,90 R$ 24,90

Lê de cima para baixo como uma tabela de faixas, e cada linha é uma pergunta. O limite prático é este: enquanto todas as condições testarem a mesma variável, na mesma direção, a escada continua honesta.

Ela para de valer quando as perguntas passam a ser sobre coisas diferentes — total, depois cliente.plano, depois endereco.uf. Nesse ponto a estrutura já não é uma faixa, é uma tabela de regras, e tabela se escreve como dado:

js
const FAIXAS = [
  { minimo: 199, etiqueta: 'grátis' },
  { minimo: 99, etiqueta: 'R$ 9,90' },
  { minimo: 49, etiqueta: 'R$ 14,90' },
];

function etiquetaDeFrete(total) {
  return FAIXAS.find((faixa) => total >= faixa.minimo)?.etiqueta ?? 'R$ 24,90';
}

console.log(etiquetaDeFrete(250));
console.log(etiquetaDeFrete(120));
console.log(etiquetaDeFrete(60));
console.log(etiquetaDeFrete(30));
grátis R$ 9,90 R$ 14,90 R$ 24,90

Mesma saída. A diferença é que acrescentar uma faixa agora é acrescentar uma linha no array, e o marketing consegue conferir a tabela sem saber ler código.

?? e &&: quando o ternário é ruído

Boa parte dos ternários que aparecem em revisão de código estão escolhendo entre “o valor” e “um padrão”. Para isso existem operadores mais curtos — e um deles está certo enquanto o outro está errado:

js
const cupomDoFormulario = '';
const apelidoDoCliente = null;
const quantidade = 0;

console.log(cupomDoFormulario ? cupomDoFormulario : 'SEMCUPOM');
console.log(cupomDoFormulario || 'SEMCUPOM');
console.log(cupomDoFormulario ?? 'SEMCUPOM');

console.log(apelidoDoCliente ?? 'cliente');
console.log(quantidade || 1);
console.log(quantidade ?? 1);
SEMCUPOM SEMCUPOM

cliente 1 0

A terceira linha da saída está vazia: ?? só substitui null e undefined, e string vazia é um valor legítimo. Já quantidade || 1 transformou o zero em um — o que numa loja significa vender uma unidade que o cliente não pediu.

Escolha assim: ?? para valor ausente, || só quando qualquer falsy deve mesmo virar o padrão, e ternário quando a condição não é sobre ausência.

Quando existe apenas o caso verdadeiro, o && resolve — com uma pegadinha:

js
const pedido = { cliente: 'Ana', total: 289.9, pago: true };

const badge = pedido.pago && 'PAGO';
const alerta = !pedido.pago && 'AGUARDANDO PAGAMENTO';

console.log(badge);
console.log(alerta);
console.log(`<span>${pedido.pago ? 'PAGO' : 'AGUARDANDO'}</span>`);
PAGO false <span>PAGO</span>

alerta virou o booleano false, não uma string vazia. Em JSX isso é inofensivo (React não renderiza false), mas numa concatenação de string você imprime a palavra “false” na tela. Se o resultado vai virar texto, use ternário com os dois braços explícitos.

Erros comuns: SyntaxError: Unexpected token ':'

O erro clássico do ternário é perder um ? no meio de uma cadeia aninhada. Os dois pontos ficam sem a pergunta correspondente:

js
const total = 120;

const etiqueta = total >= 199
  ? 'grátis'
  : total >= 99
    ? 'R$ 9,90'
    : total >= 49
      : 'R$ 14,90';

console.log(etiqueta);
file:///private/tmp/loja/t06.mjs:8 : 'R$ 14,90'; ^

SyntaxError: Unexpected token ‘:’ at compileSourceTextModule (node:internal/modules/esm/utils:318:16) at ModuleLoader.moduleStrategy (node:internal/modules/esm/translators:90:18) at #translate (node:internal/modules/esm/loader:435:20)

Node.js v24.16.0

O Node aponta a linha 8 — o : que sobrou —, mas o que falta está na linha 7: total >= 49 ficou sem o ? depois. Como todo SyntaxError, ele acontece antes de qualquer execução: o console.log da linha 10 não chegou a existir.

Ternário com efeito colateral: não

O último ponto é de disciplina. Como o ternário aceita qualquer expressão nos braços, dá para chamar função e ignorar o retorno — usando um operador de valor como se fosse um if:

js
const carrinho = { itens: 2 };

let log = [];
const registrar = (msg) => {
  log.push(msg);
  return msg;
};

carrinho.itens > 0 ? registrar('checkout liberado') : registrar('carrinho vazio');

console.log(log);

const rotulo = carrinho.itens > 0 ? 'checkout liberado' : 'carrinho vazio';
console.log(rotulo);
[ 'checkout liberado' ] checkout liberado

A linha do meio funciona: ela registrou a mensagem certa. Mas o valor produzido pelo ternário foi jogado fora, e quem lê o código precisa entrar nas duas funções para descobrir que ali existe um efeito. Isso é um if disfarçado — e um if disfarçado é pior que um if.

O critério é direto: se você usa o resultado, ternário; se você quer executar algo, if.

Como decidir na hora

situação escreva
escolher entre dois valores para atribuir ternário
escolher texto dentro de template literal ou JSX ternário
valor padrão para null/undefined ??
só existe o caso verdadeiro, em JSX &&
executar um bloco, com efeito colateral if
três ou mais faixas da mesma variável ternário em escada ou tabela de faixas
muitos valores fixos de uma variável switch ou objeto

A próxima lição da trilha de JavaScript é o switch, que é o que sobra quando a pergunta deixa de ser “verdadeiro ou falso” e passa a ser “qual dos oito valores”. O guia completo de JavaScript mostra onde isso entra no percurso.

  • operador ternario
  • condicionais
  • expressao
  • jsx
  • nullish coalescing

Perguntas frequentes

Ternário é mais rápido que if?
Não. Os dois compilam para o mesmo salto condicional e a diferença de desempenho não existe em nenhum motor moderno. A escolha é de legibilidade e de posição: o ternário devolve valor, o if executa bloco.
Posso aninhar ternários?
Pode, e uma cadeia formatada como escada, um nível por linha, ainda lê bem até três ou quatro faixas. Passando disso, ou quando as condições testam variáveis diferentes, troque por uma lista de faixas ou por switch.
Qual a diferença entre ternário e o operador ??
O ternário decide por qualquer condição que você escrever. O ?? só decide por null e undefined — zero e string vazia passam direto. Para valor padrão vindo de formulário, ?? é o correto; || derruba o zero junto.
Por que o ternário aparece tanto em React?
Porque dentro do JSX só cabe expressão, e if é instrução. Para escolher entre dois elementos no meio da marcação, o ternário é a única forma direta — junto do && quando só existe o caso verdadeiro.

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 — Operador condicional (ternário) — developer.mozilla.org
  2. MDN — Nullish coalescing operator (??) — developer.mozilla.org

Continue por aqui