[Aprenda] Diferença entre operadores ?, ?? e || no JavaScript / TypeScript

Contexto

Acredito que todo dev já ficou em dúvida sobre as diferenças entre alguns operadores do JavaScript/TypeScript. Por isso fiz esse post simples e rápido sobre as diferenças entre os operadores ?, ?? e ||. Confira logo abaixo

? - Optional Chaining

? -> Optional Chaining Operator. Permite a leitura do valor de uma propriedade localizada internamente em uma cadeia de objetos conectados, sem que a validação de cada referência da cadeia seja expressivamente realizada.

O operador ?. funciona de maneira similar ao operador . de encadeamento, exceto que, ao invés de causar um erro se a referência é nullish (null ou undefined), a expressão sofre um "curto-circuito" e retorna com um valor de undefined. Quando utilizado com uma chamada de função, retorna undefined se a função executada não existir.

Isso resulta em expressões mais curtas e simples ao acessar propriedades encadeadas quando a possibilidade de uma referência ser inexistente. Isso também pode auxiliar ao explorar o conteúdo de um objeto quando não existe garantia da existência de determinadas propriedades obrigatórias.

Exemplo

const user = {
  id: 13,
  name: "Thayto"
};

console.log(user?.name); // John
console.log(user?.fullName); // undefined, aplicação não vai quebrar.
console.log(user.fullName); // TypeError: Cannot read property ‘fullName’ of undefined, aplicação quebra.

?? - Nullish Coalesing

?? -> Nullish Coalescing Operator. É um operador lógico que retorna o seu operando do lado direito quando o seu operador do lado esquerdo é null ou undefined. Caso contrário, ele retorna o seu operando do lado esquerdo.

Exemplo

console.log(13 ?? "não encontrado") // 13
console.log(0  ?? "não encontrado") // 0

console.log("Dri"  ?? "não encontrado") // "Dri"
console.log(""     ?? "não encontrado") // ""

console.log(true  ?? "não encontrado") // true
console.log(false ?? "não encontrado") // false

console.log(undefined ?? "não encontrado") // "não encontrado"
console.log(null      ?? "não encontrado") // "não encontrado"

|| - Logical OR

|| é o Logical OR Operator A expressão Logical OR é avaliada da esquerda para a direita, é testada para possível avaliação de "curto-circuito" usando a seguinte regra:

(alguma truthy expression) || expr é avaliado em curto-circuito para a expressão verdadeira.

Curto-circuito significa que a parte expr acima não é avaliada, portanto, quaisquer efeitos colaterais de fazê-lo não têm efeito (por exemplo, se expr é uma chamada de função, a chamada nunca ocorre). Isso acontece porque o valor do operador já é determinado após a avaliação do primeiro operando.

Exemplo

console.log(13 || "não encontrado") // 13
console.log(0  || "não encontrado") // "não encontrado"

console.log("Dri"  || "não encontrado") // "Dri"
console.log(""     || "não encontrado") // "não encontrado"

console.log(true  || "não encontrado") // true
console.log(false || "não encontrado") // "não encontrado"

console.log(undefined || "não encontrado") // "não encontrado"
console.log(null      || "não encontrado") // "não encontrado"

Originalmente postado em https://thayto.com dia 31 de outubro de 2022.

Talvez no post caiba uma menção honrosa ao operador ternário também, condition ? expr1 : expr2 frequentemente usado como um atalho para a instrução if. Como nele aparece o caractere ? também, eu acabava confundindo o nome dele e do optional chaining na hora de algumas discussões rs

Parabéns pela praticidade e clareza do post ⭐

Uma dúvida, ao ínves de utilizar o "Optional Chaining" seria mais interresente tratar ou realizar alguma coisa antes de utilizar essa variável que pode ser undefined? como por exemplo:

if(user.name === undefined) {
 faça alguma coisa
}
console.log(user.name)

Ou é mais comum utilizar o optional chaining mesmo?

Vou responder uma de suas perguntas: > seria mais interresente tratar ou realizar alguma coisa antes de utilizar essa variável que pode ser undefined? Sim, mas quando você tem (por exemplo) varios objetos mesclados numa hiearquia grande (como degrau 3, etc), isso vira dor de cabeça Exemplo: ```ts interface ExemploTipo{ degrau1?: { degrau2?: { degrau3?: { algo?: string } } } } ``` Imagina fazer vários ifs para isso, claro que dá pra optimizar a estrutura, mas já da pra entender a idéia, é inviável. Ao contrário, usando Optinal Chaining eu posso simplesmente: ```ts const exemplo = ...; // alguma declaração ou chamada de função que retorne um objeto de ExemploTipo let valor = exemplo?.degrau1?.degrau2?.degrau3?.algo; // o tipo vai ser string | undefined ``` Da pra usar o nullish colleasing também para colocar um "valor padrão" se essa expressão retorna undefined.
Saqueii! Muito obrigado Miguel!

Esses três operadores são muitooo importantes, uso bastante. Confesso que sou muito fã do Nullish Coalesing, ele torna o código mais limpo e mais estético.