Why does the TypeScript compiler compile its optional chaining and null-coalescing operators, ?.
and ??
, to
// x?.y
x === null || x === void 0 ? void 0 : x.y;
// x ?? y
x !== null && x !== void 0 ? x : y
instead of
// x?.y
x == null ? void 0 : x.y
// x ?? y
x != null ? x : y
?
Odds are that behind the scenes == null
does the same two checks, but even for the sake of code length, it seems like single check would be cleaner. It adds many fewer parentheses when using a string of optional chaining, too.
Incidentally, I'm also surprised that optional chaining doesn't compile to
x == null ? x : x.y
to preserve null
vs undefined
. This has since been answered: Why does JavaScript's optional chaining to use undefined instead of preserving null?
null
... it always produces undefined
when the thing being referenced is nullish. The reason I'm putting this in a comment and not my answer below is that this really is a separate question and belongs in its own post.
You can find an authoritative answer in microsoft/TypeScript#16 (wow, an old one); it is specifically explained in this comment:
That's because of document.all [...], a quirk that gets special treatment in the language for backwards compatibility. document.all == null // true document.all === null || document.all === undefined // false In the optional chaining proposal document.all?.foo === document.all.foo but document.all == null ? void 0 : document.all.foo would incorrectly return void 0.
So there is a particular idiosyncratic deprecated obsolete wacky legacy pseudo-property edge case of type HTMLAllCollection
that nobody uses, which is loosely equal to null
but not strictly equal to either undefined
or null
. Amazing!
It doesn't seem like anyone seriously considered just breaking things for document.all
. And since the xxx === null || xxx === undefined
version works for all situations, it's probably the tersest way of emitting backward-compatible JS code that behaves according to the spec.
Success story sharing
'use strict 20XX'
that does away with all the long-deprecated features.document.all === undefined
is used instead of the safertypeof document.all === 'undefined'
... Can someone please explain?undefined
being writable are long gone.