Optional chaining e nullish coalescing
Nesta aula, você aprenderá a usar o optional chaining (?.) e o nullish coalescing (??) do JavaScript para acessar propriedades aninhadas com segurança e fornecer valores padrão, evitando erros e simplificando seu código. Vamos explorar a sintaxe, combinações comuns, pegadinhas e boas práticas, com exemplos práticos e exercícios.
O JavaScript moderno oferece dois operadores que tornam o código mais seguro e expressivo ao lidar com valores nulos ou indefinidos: o optional chaining (?.) e o nullish coalescing (??). Eles foram introduzidos no ES2020 e rapidamente se tornaram ferramentas essenciais para desenvolvedores. Nesta aula, vamos explorar como usá-los para acessar propriedades aninhadas sem medo de erros, fornecer valores padrão de forma limpa e evitar pegadinhas comuns.
Imagine que você tem um objeto que representa um usuário, e deseja acessar o endereço, mas o endereço pode não existir. Sem esses operadores, você precisaria de várias verificações if ou do operador lógico &&. Com o optional chaining e o nullish coalescing, o código fica muito mais conciso e legível. Vamos ver como isso funciona na prática.
?. (Optional Chaining)
O operador ?. permite que você acesse propriedades de um objeto de forma segura, interrompendo a avaliação se o valor for null ou undefined. Em vez de lançar um erro, ele retorna undefined.
Considere o seguinte objeto:
const user = {
name: 'Ana',
address: {
city: 'São Paulo'
}
};
console.log(user.address.city); // "São Paulo"
Se address não existir, user.address.city lançará um erro TypeError. Com o optional chaining, você pode escrever:
console.log(user.address?.city); // undefined, sem erro
O ?. também pode ser usado com chamadas de função e acesso a índices. Por exemplo:
const result = someObject.method?.(); // se someObject.method não for função, retorna undefined
const firstItem = array?.[0]; // se array for undefined/null, retorna undefined
Uma observação importante: o optional chaining só verifica o valor imediatamente à esquerda do ?.. Por exemplo, user.address?.city verifica se user.address é null/undefined; se for, retorna undefined. Se user for null, você ainda precisa usar user?.address?.city.
?? (Nullish Coalescing)
O operador ?? fornece um valor padrão quando o operando à esquerda é null ou undefined. Ele é diferente do operador lógico ||, que considera valores falsy como 0, '', false, NaN como 'vazios' e os substitui pelo valor padrão. O ?? é mais preciso: só ativa quando o valor é null ou undefined.
Veja a diferença:
const valor1 = 0;
const valor2 = null;
console.log(valor1 || 'padrão'); // "padrão" (porque 0 é falsy)
console.log(valor1 ?? 'padrão'); // 0 (porque 0 não é null/undefined)
console.log(valor2 || 'padrão'); // "padrão"
console.log(valor2 ?? 'padrão'); // "padrão"
Isso é extremamente útil quando você quer tratar apenas valores ausentes, sem interferir em valores válidos como 0 ou ''.
Combinando com defaults
O optional chaining e o nullish coalescing podem ser combinados para criar padrões de código muito robustos. Por exemplo, ao acessar uma propriedade aninhada que pode não existir, você pode fornecer um valor padrão:
const user = {
name: 'Ana',
address: null
};
const city = user.address?.city ?? 'Cidade não informada';
console.log(city); // "Cidade não informada"
Nesse exemplo, se user.address for null, o ?. retorna undefined, e o ?? fornece o valor padrão. Se user.address existir, mas city for null, também retorna o padrão.
Outra aplicação comum é em configurações ou parâmetros de função:
function greet(config) {
const name = config?.name ?? 'Visitante';
console.log(`Olá, ${name}!`);
}
greet({ name: 'João' }); // Olá, João!
greet({}); // Olá, Visitante!
greet(null); // Olá, Visitante!
Isso elimina a necessidade de verificações manuais e torna o código mais limpo.
Pegadinhas
Apesar de serem poderosos, esses operadores têm algumas armadilhas que você deve conhecer.
1. Não é possível usar ?. em uma atribuição (exceto em alguns casos com avaliação curta). Por exemplo, obj?.prop = valor é inválido. Você precisa verificar antes de atribuir ou usar lógica alternativa.
2. O ?? não pode ser combinado diretamente com || ou && sem parênteses. Isso gera um erro de sintaxe, pois a mistura é ambígua. Por exemplo, a ?? b || c é inválido; use parênteses: (a ?? b) || c.
3. O optional chaining não impede erros em outras partes da cadeia. Ele só protege o acesso à propriedade imediatamente à esquerda. Se você tiver user.address.street?.name e user.address for null, o erro ocorrerá ao acessar .street antes do ?..
4. Uso em chamadas de função: se você usar obj.method?.(), o ?. verifica se obj.method é null/undefined. Se for, retorna undefined, mas se for outro valor não-chamável (como um número), ele tentará chamar e lançará um erro. Portanto, o ?. não valida se é uma função, apenas se não é null/undefined.
5. Compatibilidade: embora seja amplamente suportado em navegadores modernos, verifique se o seu alvo de compilação (por exemplo, Babel) suporta esses recursos, especialmente em ambientes mais antigos.
Boas Práticas
Ao usar esses operadores, prefira o ?? em vez de || para valores padrão quando você quer preservar valores como 0 ou ''. Use o optional chaining para acessar propriedades aninhadas em objetos que podem ser null/undefined, mas não abuse: se a estrutura for garantida, não é necessário. Sempre teste os casos de borda, como valores falsy e null.
Referências
- MDN - Optional chaining
- MDN - Nullish coalescing
- JavaScript.info - Optional chaining
- JavaScript.info - Nullish coalescing
- ECMA-262 - Optional Chaining Spec
- ECMA-262 - Nullish Coalescing Spec
Exercícios
- Dado o objeto
const data = { user: { profile: { name: 'Maria' } } }, escreva uma expressão que acessedata.user.profile.agede forma segura, retornandoundefinedse algo não existir. - Usando o operador
??, escreva uma função que receba um objetoconfige retorne o valor deconfig.retriesse for um número, ou3como padrão. Considere queconfigpode ser null/undefined. - Qual é a diferença entre
||e??? Dê um exemplo onde eles produzem resultados diferentes. - Explique por que
obj?.prop = valueé um erro de sintaxe e sugira uma alternativa. - O que o código a seguir imprime? Justifique sua resposta.
const a = { b: null }; console.log(a.b?.c ?? 'padrão');
data.user.profile?.age ou data?.user?.profile?.age. A primeira é suficiente se data.user.profile pode ser null, mas se qualquer um dos níveis pode ser null, use a versão com ?. em todos os níveis.
function getRetries(config) {
return config?.retries ?? 3;
}
Se config for null/undefined, retorna 3. Se config.retries for null/undefined, também retorna 3. Se for um número (incluindo 0), retorna esse número.
|| retorna o valor à direita se o valor à esquerda for falsy (0, '', false, NaN, null, undefined). O ?? retorna o valor à direita apenas se o valor à esquerda for null ou undefined. Exemplo: 0 || 'padrão' retorna 'padrão', enquanto 0 ?? 'padrão' retorna 0.
if (obj) obj.prop = value; ou use Object.assign com uma condição.
"padrão". Porque a.b é null, então a.b?.c retorna undefined, e o ?? fornece o valor padrão "padrão".