segunda-feira, 16 de maio de 2022

Operador de Encadeamento Opcional (?.) (Optional Chaining) em Javascript

O Operador de Encadeamento Opcional (

?.
), ou Optional Chaining, é um operador do Javascript que permite acessar propriedades de um determinado objeto sem fazer grandes verificações explícitas (usando um
if
, ou um operador condicional ternário (
condicao ? expr1 : expr2
), por exemplo) sobre a existência do próprio objeto. E isso é incrível principalmente porque é bem comum termos diversos objetos encadeados, onde alguns deles podem ser
null
ou
undefined
em algum estado de certa aplicação.

Problema inicial

Para ficar mais claro, vamos ver um exemplo bem simples:

Considere que, em algum estado da minha aplicação, teremos um objeto usuario que terá outro objeto encadeado chamado contato e que esse terá algumas propriedades de contato, como telefone, por exemplo:

const usuario = {
contato: {
telefone: '9999-9999'
}
};

Mas vamos supor que esses dados de contato não estejam disponíveis em um estado inicial, então meu objeto usuario estará vazio:

const usuario = {};

Apenas com o que temos acima, não podemos saber em qual estado nossa aplicação está. Logo, não conseguiremos saber se o objeto contato existe no objeto usuario. O que acontece se tentarmos acessar as propriedades desse objeto em diferentes estados então?

Bem, se o objeto contato está no usuario como o esperado, então funcionará corretamente:

const usuario = {
contato: {
telefone: '9999-9999'
}
};
console.log('Telefone:', usuario.contato.telefone);
// ✅ Funciona

Mas se o objeto contato ainda não está no usuario, a história muda:

const usuario = {};
console.log('Telefone:', usuario.contato.telefone);
// ❌ Uncaught TypeError:
// Cannot read properties of undefined (reading 'telefone')

O objeto contato ainda não foi definido (

undefined
) no objeto usuario, logo não podemos acessar suas propriedades.

Utilizando o operador de encadeamento opcional

Como já dito, há diversas formas de resolver isso, mas o operador de encadeamento opcional deixa tudo bem limpo e simples:

console.log('Telefone:', usuario.contato?.telefone);
// here ^
  • Se o
    usuario.contato
    existe, então conseguiremos acessar a propriedade
    telefone
    normalmente e exibir o dado.
  • Já se o
    usuario.contato
    for
    null
    ou
    undefined
    , então o operador de encadeamento opcional retornará
    undefined
    e nem tentará acessar a propriedade
    telefone
    .

Possibilidades

Além de objetos encadeados, podemos usar o operador em funções, e até mesmo arrays:

  • Funções:

    const foto = usuario.exibirFoto?.();

    Só executará a função exibirFoto caso ela não seja

    null
    ou
    undefined
    . Caso contrário, foto será
    undefined
    .

  • Arrays:

    const usuario = {
    contatos: [{ telefone: '9999-9999' }, { telefone: '8888-8888' }]
    };
    const primeiroTelefone = usuario.contatos?.[0]?.telefone;

    Aqui podemos ver duas possibilidades:

    • Em
      contatos?.
      , verificamos se o array contatos já existe no objeto usuario, antes de prosseguirmos acessando o resto da cadeia (que nesse caso é tentar acessar o primeiro elemento do array).
    • Se
      contatos?.
      nos retornou o array (ao invés de
      undefined
      ), como esperado, então prosseguimos e verificamos se o primeiro elemento existe:
      [0]?.
      .
    • Caso tenhamos passado por ambos os operadores de encadeamento opcional, então conseguimos acessar a propriedade telefone normalmente. Caso não, teremos
      undefined
      como valor da constante primeiroTelefone.