evanw / esbuild

An extremely fast bundler for the web
https://esbuild.github.io/
MIT License
37.98k stars 1.14k forks source link

When transform nullish coalescing it transform != null which may lead to wrong result #3772

Closed IrisChen7 closed 4 months ago

IrisChen7 commented 4 months ago

esbuild version: esbuild node version: 16.20.0

Below is my code

import * as esbuild from 'esbuild'

let ts = 'a = b ?? 1'
let result = await esbuild.transform(ts, {
  target: [
    'es6',
  ],
})
console.log(result.code)

Run result: a = b != null ? b : 1;

Expected result: a = b !== null && a !== undefined ? b : 1;

Since result of 0 ?? 1 is 0, this may lead to wrong result, is there any settings that can make it right?

hyrious commented 4 months ago

a == null is effectively equal to a === null || a === undefined, as the spec of ECMAScript said. So it is a totally correct transform.

$ node -p 'a=0;b=1;a??b'
0

$ node -p 'a=0;b=1;a!=null?a:b'
0
magic-akari commented 4 months ago

The only difference is document.all. If you are using Babel, you can achieve code as concise as esbuild's by set https://babeljs.io/docs/assumptions#nodocumentall.

Apart from document.all, they are equivalent.

It appears that esbuild has adopted this strategy by default.

evanw commented 4 months ago

Yes, the document.all edge case is only the reason why some tools have different output than esbuild here. Specifically document.all is the only value in all of JavaScript for which x != null is false but x !== null && x !== undefined is true.

But it's such an obscure edge case that I have decided I don't care about it. FWIW terser, another popular JavaScript minifier, has also decided that they don't care about document.all either: https://github.com/terser/terser/issues/408.

It's ancient web history and doesn't belong in modern JavaScript code. It's not worth bloating everyone's code by transforming ?? into this double-comparison just to handle the document.all value that no one should be using in the first place.

I'm closing this issue as I won't be changing anything here.

Since result of 0 ?? 1 is 0, this may lead to wrong result, is there any settings that can make it right?

Note that 0 ?? 1 and 0 != null ? 0 : 1 are both 0. So esbuild is correct.