foo && await foo();
is not the same as await foo?.();
this will work in most cases but subtly, the await wraps the undefined case into a Promise, while the original code would skip the await altogether.String regular expression matching returns null, not undefined, so rewriting code such as:
const match = str.match(/reg(ex)/);
return match && match[1];
is not the same thing as: return match?.[1];
because the latter returns undefined, not null, in case of match failure. This can cause problems if subsequent code expects null for match failure. An equivalent rewrite would be: return match?.[1] ?? null;
which is longer than the original and arguably less clear.A common idiom to catch and ignore exceptions can interact poorly with optional chaining:
const v = await foo().catch(_ => {});
return v?.field; // property 'field' does not exist on type 'void'
This can be easily remedied by changing the first line to: const v = await foo().catch(_ => undefined);
Of course, these new operators are very welcome and will greatly simplify and help increase the safety of much existing code. But as in all things syntax, being judicious about usage of these operators is important to maximize clarity.