|
I just did some refactoring on a medium size code base and here are a few things to watch out for when adopting optional chaining and the new null coalescing operator: 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. |
It's a shame JS at the beginning doubled down on the "billon dollar mistake" [1] with two(!) kinds of NULL instead of just using Maybe/Option.
Ah well, if it were good it wouldn't be popular :/
[1] https://www.lucidchart.com/techblog/2015/08/31/the-worst-mis...