Fala, Gelson! Tudo bem?
São coisas diferentes mesmo.
O ponto de exclamação (!
) indica ao compilador que não existe a possibilidade daquela variável ser null
ou undefined
. Acontece de às vezes o compilador não ser capaz de prever um comportamento, ou se você usar alguma biblioteca que não está bem tipada, o compilador não tem certeza do que pode chegar na variável. Assim, o !
é útil para esses casos. Se quiser saber mais sobre, o nome desse operador é Non-null Assertion Operator.
Já no caso do ponto de interrogação (?
), é quando queremos acessar a propriedade de um objeto que pode ou não ser nulo. Diferente do !
, aqui nós não assumimos responsabilidade nenhuma, na verdade, tiramos de nós a responsabilidade de garantir que o objeto exista. Porque quando usado, em tempo de execução, se o objeto existir, a propriedade é acessada, se o objeto não existir (null
ou undefined
), a expressão não gera um erro, apenas retorna undefined
. O nome desse operador é Optional Chaining Operator. Seria similar a fazer o seguinte:
if (obj) {
return obj.propriedade;
} else {
return undefined;
}
Espero que ajude!