Introdução: a pergunta que atormenta os iniciantes
\nVocê já escreveu em TypeScript e recebeu um erro como Cannot read property 'name' of undefined? Uma dor familiar, certo? Especialmente quando se trabalha com dados vindos do servidor ou com objetos profundamente aninhados. É nesses momentos que surge a pergunta: "Existe um operador em TypeScript que permite acessar propriedades com segurança, sem medo de que tudo desabe?"
No Stack Overflow, essa pergunta acumulou milhares de visualizações. E a resposta é sim, esse operador existe. Mais do que isso, ele também existe em JavaScript (desde ES2020) e funciona "de fábrica" no TypeScript. Ele se chama optional chaining (encadeamento opcional) e tem a aparência familiar de ?.. Neste artigo, não apenas mostraremos como usá-lo, mas também vamos olhar sob o capô: como o compilador TypeScript transforma essa sintaxe elegante em código JavaScript seguro.
Como se chama o operador ?. em TypeScript?
\nVamos começar pelo principal. Na comunidade de desenvolvedores, esse operador é chamado de várias formas:
\n- \n
- Optional chaining (encadeamento opcional) — nome oficial na especificação ECMAScript. \n
- Operador de acesso seguro (Safe navigation operator) — veio de outras linguagens, como C# e Swift. \n
- Operador condicional nulo (Null-conditional operator) — encontrado na documentação da Microsoft. \n
Mas a essência é a mesma: ?. permite acessar uma propriedade de um objeto e, se o objeto for null ou undefined, em vez de um erro, simplesmente obtemos undefined. Isso não é mágica, é apenas açúcar sintático que torna o código mais limpo e seguro.
Sintaxe básica
\nA sintaxe é extremamente simples. Em vez de escrever:
\nif (user && user.profile && user.profile.name) {\n console.log(user.profile.name);\n}\nVocê escreve:
\nconsole.log(user?.profile?.name);\nSe user for undefined, toda a cadeia é interrompida e undefined é exibido no console. Sem erros, sem verificações extras. Que beleza!
Como funciona internamente: compilação de TypeScript para JavaScript
\nTypeScript é uma extensão do JavaScript. Ele não executa o código diretamente, mas o compila em JS comum. Então, vamos ver no que se transforma nosso elegante user?.profile?.name após a compilação.
Exemplo: optional chaining simples
\nCódigo original em TypeScript:
\nconst name = user?.profile?.name;\nApós a compilação (alvo ES5):
\nvar name = user === null || user === void 0 ? void 0 : user.profile === null || user.profile === void 0 ? void 0 : user.profile.name;\nO que acontece aqui? O compilador gera um operador ternário que verifica cada nível de aninhamento para null ou undefined. Se o valor for null ou undefined, retorna void 0 (uma forma confiável de obter undefined em engines antigos). Caso contrário, prossegue. Basicamente, é aquele código "manual" que escrevíamos antes, mas agora gerado pela máquina.
Exemplo: optional chaining com chamada de função
\nO operador ?. funciona não apenas com propriedades, mas também com chamadas de função. Suponha que temos um método getAddress que pode estar ausente:
const address = user?.getAddress?.();\nApós a compilação:
\nvar address = user === null || user === void 0 ? void 0 : (typeof user.getAddress === "function" ? user.getAddress() : void 0);\nObserve: o compilador não apenas verifica null, mas também confirma que getAddress é uma função antes de chamá-la. Se não for uma função, retorna undef