为什么 TypeScript 编译器通过两次检查来编译其可选的链接和空合并运算符?

Why does the TypeScript compiler compile its optional chaining and null-coalescing operators with two checks?

为什么 TypeScript 编译器将其 optional chaining and null-coalescing 运算符 ?.?? 编译为

// x?.y
x === null || x === void 0 ? void 0 : x.y;

// x ?? y
x !== null && x !== void 0 ? x : y

而不是

// x?.y
x == null ? void 0 : x.y

// x ?? y
x != null ? x : y

?

很可能在幕后 == null 进行相同的两次检查,但即使考虑到代码长度,似乎单次检查会更清晰。当使用一串可选链接时,它也添加了更少的括号。

顺便说一句,我也很惊讶可选链接没有编译成

x == null ? x : x.y

保留 nullundefined。这已得到回答:

您可以在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.

所以有一个 particular idiosyncratic deprecated obsolete wacky legacy edge case of type HTMLAllCollection 没有人使用,它大致等于 null 但不严格等于 undefinednull。太棒了!

似乎没有人认真考虑 打破 东西 document.all。由于 xxx === null || xxx === undefined 版本适用于所有情况,因此它可能是发出行为符合规范的向后兼容 JS 代码的最简洁方式。