Menu

Optional Chaining (?.) no JavaScript: guia prático

Entenda como o operador ?. permite acessar propriedades aninhadas, arrays e métodos sem quebrar a aplicação quando o valor é null ou undefined.

O problema: acessar propriedades aninhadas é frágil

Acessar propriedades aninhadas em um objeto funciona super bem — até o momento em que um dos níveis simplesmente não existe:

index.js
Output
Click Run to see the output here.

user.address é undefined, e tentar ler .city a partir de undefined lança TypeError: Cannot read properties of undefined. Dados do mundo real — respostas de API, JSON parseado, consultas ao DOM — estão cheios de campos que podem ou não existir, e ficar escrevendo verificações defensivas para cada nível vira uma bagunça rapidinho:

const city = user && user.address && user.address.city;

Dá pra ler com dois níveis. Vira um pesadelo com quatro. O operador ?. é a solução mais limpa.

?. faz curto-circuito em null e undefined

O optional chaining acessa uma propriedade apenas se o valor antes dele não for null nem undefined. Quando for, a expressão inteira devolve undefined e a avaliação para por aí.

index.js
Output
Click Run to see the output here.

Na primeira linha, name é lido normalmente. Na segunda, ao chegar em user.address, o valor é undefined e a cadeia é interrompida ali — o resto nem chega a ser executado. A terceira linha daria erro sem o ?., porque .toUpperCase() seria chamado em undefined; com o ?., a expressão inteira simplesmente resolve para undefined, sem estourar.

O modelo mental é esse: ?. significa "se o que vem antes de mim for null ou undefined, desiste e devolve undefined — caso contrário, segue em frente."

Funciona também em arrays e chamadas de função

São três sintaxes para a mesma ideia:

index.js
Output
Click Run to see the output here.
  • ?.[...] para acessar arrays ou propriedades dinâmicas.
  • ?.() para chamar algo que pode ou não ser uma função.
  • ?.name para acessar propriedades comuns.

Os três fazem short-circuit da mesma forma. user?.notAMethod?.() não quebra mesmo quando notAMethod não existe — o segundo ?. encontra undefined e para por ali.

Isso cai como uma luva para callbacks opcionais:

index.js
Output
Click Run to see the output here.

Chega de ficar colocando if (typeof onDone === "function") antes de cada chamada.

null e undefined disparam o curto-circuito

Esse é o detalhe que pega muita gente desprevenida. O ?. só se importa com valores nullish. Outros valores falsy — 0, "", false, NaN — são alvos perfeitamente válidos para continuar a cadeia (na medida em que o autoboxing permite, claro):

index.js
Output
Click Run to see the output here.

data.count vale 0, que é falsy mas não é nullish. Por isso o ?.toFixed(2) é executado normalmente e retorna "0.00". Compare com o comportamento do &&:

index.js
Output
Click Run to see the output here.

A versão com && devolve 0 porque data.count é falsy e faz curto-circuito. Já a versão com ?. devolve "0.00", já que 0 não é nullish. Se o seu objetivo é parar também no 0, use &&. Agora, se você quer parar só quando "o valor não existe", o ?. é o certo.

A posição do ? faz diferença

O ?. protege o valor que vem antes dele — não o que vem depois. Por isso, coloque-o no nível que pode estar ausente:

index.js
Output
Click Run to see the output here.

Todos os três funcionam aqui porque, na verdade, não falta nada. Mas se config.server pudesse ser undefined, você precisaria de config.server?.host — colocar ?. antes de server não ajudaria, já que o problema é tentar ler .host de um server inexistente.

Uma boa regra prática: coloque ?. em cada nível onde o valor anterior pode realmente ser nulo ou indefinido. Espalhar ?. em todo ponto "por via das dúvidas" acaba escondendo bugs e deixando o código mais poluído.

Atribuição com ?. não funciona

O optional chaining é só para leitura. Você não pode usá-lo no lado esquerdo de uma atribuição:

user?.address?.city = "Paris";   // SyntaxError

Faz sentido se você parar pra pensar — o que significaria atribuir um valor a uma propriedade de undefined? Se a ideia é atribuir só quando o objeto pai existe, escreva assim:

index.js
Output
Click Run to see the output here.

Quando usar (e quando não usar)

O ?. brilha quando um valor é legitimamente opcional:

  • Respostas de API em que certos campos podem ou não vir.
  • Consultas ao DOM: document.querySelector(".banner")?.remove().
  • Callbacks que podem não ter sido passados: options.onError?.(err).
  • Chamadas encadeadas em libs onde resultados intermediários podem ser null.

Agora, é a ferramenta errada quando o valor sempre deveria existir. Sair espalhando ?. só pra calar erros nesses casos transforma um bug barulhento e fácil de achar ("TypeError na linha 42") num bug silencioso — uma variável que aparece misteriosamente como undefined três funções adiante. Quando algo tem que estar lá, deixe estourar: o stack trace está te fazendo um favor.

Um exemplo realista

Extraindo um valor de uma resposta de API que pode vir incompleta:

index.js
Output
Click Run to see the output here.

Cada ?. cuida de um nível de incerteza. O avatarUrl acaba virando undefined sem drama. Já o onClick?.() só chama o handler se ele estiver lá de fato.

Repare no ?? da linha do displayName — essa é a outra metade do padrão. O ?. devolve undefined quando algo está faltando; já o ?? permite colocar um valor padrão sem tropeçar em valores falsy legítimos como 0 ou "".

Próximo passo: nullish coalescing

?. e ?? são a mesma ideia aplicada a problemas diferentes: os dois tratam null e undefined como "ausente" e deixam os demais valores falsy em paz. No próximo tópico, vamos ver como o ?? entrega valores padrão sensatos — e por que o || vem fazendo isso errado em silêncio há anos.

Perguntas frequentes

O que faz o operador ?. no JavaScript?

O operador ?. acessa uma propriedade, índice de array ou método somente se o valor antes dele não for null nem undefined. Quando é, a expressão inteira é curto-circuitada e retorna undefined em vez de lançar um erro. Assim, user?.address?.city não quebra mesmo se user ou address não existirem.

Quando usar optional chaining no JavaScript?

Use ?. quando o valor realmente pode não existir — respostas de API com campos opcionais, buscas no DOM que talvez não encontrem o elemento, callbacks que podem ou não ser passados. Não use para esconder bugs em lugares onde o valor deveria sempre existir: nesses casos, um valor ausente é uma informação importante que você quer ver explodindo na sua cara.

Qual a diferença entre ?. e && no JavaScript?

Na maioria dos casos o resultado é igual, mas o ?. só faz curto-circuito em null ou undefined, enquanto o && faz em qualquer valor falsy — incluindo 0, '' e false. Por exemplo, obj && obj.count retorna 0 quando count é 0; já obj?.count também retorna 0, mas a cadeia só é interrompida nos valores nullish, o que costuma ser o comportamento que você quer.

Dá para usar optional chaining com arrays e chamadas de função?

Sim. arr?.[0] lê com segurança um índice de array, e fn?.() executa a função apenas se ela existir. A regra é a mesma nos dois casos: se o valor antes do ?. for null ou undefined, a expressão toda vira undefined e nada mais é executado.

Aprenda a programar com o Coddy

COMEÇAR