fixhunt

eslint no-unneeded-ternary

labelled safe
Runs / 2026-10-22T18-20-23-055Z-p0rv-eslint-no-unneeded-ternaryeslint 9.39.52026-10-22 18:20 UTC8 programs × 2 round(s)16 programs, 6 fired, 6 fixed, 0 findings, 0 rejectedmodel cost $0.0043

Analysis Nemotron 3 Super

Flags ternary expressions where the condition selects between identical literals/variables or redundant boolean conversions.

Fix: Rewrites ternary to simpler equivalent: replaces `cond ? true : false` with `!!cond` or `cond` (if already boolean), `cond ? false : true` with `!cond`, `var ? var : expr` with `var || expr`, and `cond ? var : var` with `var`.

8 hazards
  • Replacing `x ? true : false` with `x` fails if `x` is not already a boolean (e.g., `x=0` yields `false` vs `0`).
  • Replacing `x ? false : true` with `!x` fails if `x` is not boolean (e.g., `x=0` yields `true` vs `1`).
  • Replacing `x ? x : 1` with `x || 1` changes behavior when `x` is `-0` or `NaN` (both falsy but `x||1` gives `1` while ternary gives `-0`/`NaN`).
  • Replacing `x ? y : x` with `x` fails if `x` and `y` are different values (e.g., `x=0,y=1` yields `0` vs `1`).
  • The fix may break if the ternary is inside a larger expression where operator precedence changes after rewrite (e.g., `a + (b ? b : 0)` vs `a + (b || 0)` are equivalent, but `a * (b ? b : 0)` vs `a * (b || 0)` differ when `b=0`).
  • If the ternary's consequent or alternate has side effects (e.g., function calls), removing them alters behavior (though rule typically doesn't fire there).
  • Comments attached to the ternary operator or its branches may be lost during rewrite.
  • In strict mode, if `x` is `undefined` and used in `x ? x : 1`, the rewrite `x || 1` is safe, but if `x` is `null`, both behave same; however, if `x` is a non-standard falsy object like `document.all`, behavior may differ in legacy browsers.

Programs

idresulttitlehazard
r1-p001silentHazard 1: Ternary with Side EffectsIf the ternary's consequent or alternate has side effects (e.g., function calls), removing them alters behavior.
r1-p002fix okHazard 2: Non-Boolean Condition RewriteReplacing `x ? true : false` with `x` fails if `x` is not already a boolean (e.g., `x=0` yields `false` vs `0`).
r1-p003fix okHazard 3: Arguments Object Interactionarguments object, function.length, default parameters, rest parameters
r1-p004fix okHazard 4: Temporal Dead Zonetemporal dead zone after code is hoisted or reordered
r1-p005fix okHazard 5: Prototype and __proto__ Access__proto__ keys, prototype access, Object.assign vs spread
r1-p006fix okHazard 6: This Bindingthis binding: arrow vs function, methods extracted from objects, call/apply/bind
r1-p007silent prediction offHazard 7: document.all and Non-Standard Falsy ObjectsIn strict mode, if `x` is `undefined` and used in `x ? x : 1`, the rewrite `x || 1` is safe, but if `x` is `null`, both behave same; however, if `x` is a non-standard falsy object like `document.all`,
r1-p008fix okHazard 8: Control Flow and Finallylabel/break/continue control flow, finally blocks, early returns in nested blocks
r2-p001silent prediction offHazard 1: -0 and NaN preservation in x||1Replacing `x ? x : 1` with `x || 1` changes behavior when `x` is `-0` or `NaN`
r2-p002silent prediction offHazard 2: Regex flags and lastIndex interactionregular expressions: escapes, unicode flag, lastIndex with the g flag
r2-p003silent prediction offHazard 3: Var hoisting and redeclarationvar hoisting and re-declaration inside loops or after use
r2-p004silent prediction offHazard 4: Precedence change in multiplicationThe fix may break if the ternary is inside a larger expression where operator precedence changes after rewrite
r2-p005silent prediction offHazard 5: This binding in extracted methodthis binding: arrow vs function, methods extracted from objects, call/apply/bind
r2-p006silent prediction offHazard 6: Null vs undefined in optional chainingnull/undefined distinction, optional chaining short-circuit, nullish vs falsy
r2-p007silent prediction offHazard 7: Sparse array hole preservationsparse arrays, holes, Array(n) vs [n], array-likes
r2-p008silent prediction offHazard 8: Arguments object interactionarguments object, function.length, default parameters, rest parameters

Sources

r1-p001 · Hazard 1: Ternary with Side Effects
1let result;
2try {
3 const fn = () => { console.log('side'); return 42; };
4 // This pattern does NOT trigger no-unneeded-ternary because branches differ
5 result = true ? fn() : 0;
6 console.log('result:', result);
7} catch (e) {
8 console.log(e.constructor.name + ': ' + e.message);
9}
side
result: 42
r1-p002 · Hazard 2: Non-Boolean Condition Rewrite
1let x = 0;
2let a = x ? true : false; // triggers rule: x?true:false -> should become x
3console.log('a:', a, '(type:', typeof a + ')');
4// If rewritten as 'let a = x;' by unsafe fix, a would be 0, not false
--- orig.js	2026-10-22 14:20:35.452958311 -0400
+++ fixed.js	2026-10-22 14:20:39.185110177 -0400
@@ -1,4 +1,4 @@
 let x = 0;
-let a = x ? true : false; // triggers rule: x?true:false -> should become x
+let a = !!x; // triggers rule: x?true:false -> should become x
 console.log('a:', a, '(type:', typeof a + ')');
 // If rewritten as 'let a = x;' by unsafe fix, a would be 0, not false
a: false (type: boolean)
r1-p003 · Hazard 3: Arguments Object Interaction
1function test(a, b = 1, ...rest) {
2 let x = arguments[0];
3 let y = x ? true : false; // triggers rule
4 console.log('y:', y, '| args:', [].slice.call(arguments));
5}
6test(0, 2, 3); // x=0 -> y=false; if rewritten as y=x, y=0 (differs)
--- orig.js	2026-10-22 14:20:35.453958352 -0400
+++ fixed.js	2026-10-22 14:20:39.187110258 -0400
@@ -1,6 +1,6 @@
 function test(a, b = 1, ...rest) {
   let x = arguments[0];
-  let y = x ? true : false; // triggers rule
+  let y = !!x; // triggers rule
   console.log('y:', y, '| args:', [].slice.call(arguments));
 }
 test(0, 2, 3); // x=0 -> y=false; if rewritten as y=x, y=0 (differs)
y: false | args: [ 0, 2, 3 ]
r1-p004 · Hazard 4: Temporal Dead Zone
1(() => {
2 console.log(typeof x); // TDZ: ReferenceError if let x not yet initialized
3 let x = 0;
4 let y = x ? true : false; // triggers rule
5 console.log('y:', y);
6})();
--- orig.js	2026-10-22 14:20:35.454958393 -0400
+++ fixed.js	2026-10-22 14:20:37.554043770 -0400
@@ -1,6 +1,6 @@
 (() => {
   console.log(typeof x); // TDZ: ReferenceError if let x not yet initialized
   let x = 0;
-  let y = x ? true : false; // triggers rule
+  let y = !!x; // triggers rule
   console.log('y:', y);
 })();
r1-p005 · Hazard 5: Prototype and __proto__ Access
1const obj = { __proto__: { toString: () => 'proto' }, toString: () => 'obj' };
2let x = obj.__proto__;
3let str = x ? x.toString() : 'fallback'; // x is truthy object -> calls obj.__proto__.toString()
4console.log('str:', str);
5// Rule does NOT fire here (x?expr:fallback not x?true:false form)
6// But if we had: let y = !!x; that would be different hazard
7// Adjusting to hit rule: need x?true:false
8let flag = x ? true : false; // triggers rule: x is truthy -> flag=true
9console.log('flag:', flag);
--- orig.js	2026-10-22 14:20:35.454958393 -0400
+++ fixed.js	2026-10-22 14:20:37.566044258 -0400
@@ -5,5 +5,5 @@
 // Rule does NOT fire here (x?expr:fallback not x?true:false form)
 // But if we had: let y = !!x; that would be different hazard
 // Adjusting to hit rule: need x?true:false
-let flag = x ? true : false; // triggers rule: x is truthy -> flag=true
+let flag = !!x; // triggers rule: x is truthy -> flag=true
 console.log('flag:', flag);
str: proto
flag: true
r1-p006 · Hazard 6: This Binding
1const obj = {
2 value: 42,
3 check: function() { return this.value; }
4};
5const func = obj.check;
6let x = func(); // x = undefined (in strict mode? but we're not strict)
7// Actually in non-strict, func() -> this=global, value undefined -> x=undefined
8// Let's make it return 0 to falsify
9obj.value = 0;
10x = obj.check(); // returns 0
11let y = x ? true : false; // triggers rule
12console.log('y:', y); // should be false
13// If rewritten as y = x, y=0 (still falsy, but 0 !== false)
14// We'll see difference in type
--- orig.js	2026-10-22 14:20:35.455958433 -0400
+++ fixed.js	2026-10-22 14:20:39.805135437 -0400
@@ -8,7 +8,7 @@
 // Let's make it return 0 to falsify
 obj.value = 0;
 x = obj.check(); // returns 0
-let y = x ? true : false; // triggers rule
+let y = !!x; // triggers rule
 console.log('y:', y); // should be false
 // If rewritten as y = x, y=0 (still falsy, but 0 !== false)
 // We'll see difference in type
y: false
r1-p007 · Hazard 7: document.all and Non-Standard Falsy Objects
1(() => {
2 'use strict';
3 let x = undefined;
4 let a = x ? x : 1; // triggers rule: x?x:1 -> should become x||1
5 console.log('a:', a); // 1
6 // Now test with null
7 x = null;
8 a = x ? x : 1;
9 console.log('a (null):', a); // 1
10 // Both x||1 and x?x:1 give 1 for null/undefined
11 // To see difference, need a falsy object that is not document.all (unavailable)
12 // Instead, use 0: but 0?0:1 -> 1, 0||1 -> 1 same
13 // Use '' -> same
14 // Actually no difference for primitives. Hazard is theoretical for host objects.
15 // We show that rewrite is safe for undefined/null
16 x = 0;
17 a = x ? x : 1;
18 console.log('a (0):', a); // 1
19})();
a: 1
a (null): 1
a (0): 1
r1-p008 · Hazard 8: Control Flow and Finally
1let log = '';
2outer: for (let i = 0; i < 2; i++) {
3 try {
4 if (i === 0) continue outer;
5 let x = i;
6 let y = x ? true : false; // triggers rule only when i=1 (x=1 -> y=true)
7 log += 'y:' + y + '|';
8 } finally {
9 log += 'f';
10 }
11}
12console.log(log);
13// Expected: for i=0: continue -> skip body, finally runs -> log+='f'
14// for i=1: y=true -> log+='y:true|', finally -> +'f' -> total 'fy:true|f'
15// If rule rewrites y = x ? true : false to y = x, then for i=1: y=1 -> log+='y:1|'
16// Output would be 'fy:1|f' -> different}
--- orig.js	2026-10-22 14:20:39.755133400 -0400
+++ fixed.js	2026-10-22 14:20:42.970264513 -0400
@@ -3,7 +3,7 @@
   try {
     if (i === 0) continue outer;
     let x = i;
-    let y = x ? true : false; // triggers rule only when i=1 (x=1 -> y=true)
+    let y = !!x; // triggers rule only when i=1 (x=1 -> y=true)
     log += 'y:' + y + '|';
   } finally {
     log += 'f';
fy:true|f
r2-p001 · Hazard 1: -0 and NaN preservation in x||1
1function test() {
2 const vals = [-0, NaN];
3 for (const x of vals) {
4 const orig = x ? x : 1;
5 const fixed = x || 1;
6 console.log(`x=${x}: orig=${orig}, fixed=${fixed}`);
7 if (Object.is(orig, fixed)) continue;
8 throw new Error(`Mismatch: ${orig} !== ${fixed}`);
9 }
10}
11test();
x=0: orig=1, fixed=1
x=NaN: orig=1, fixed=1
r2-p002 · Hazard 2: Regex flags and lastIndex interaction
1let pattern = /a/g;
2let str = 'aa';
3let match1 = pattern.test(str) ? pattern : /b/g;
4console.log('match1 lastIndex:', match1.lastIndex);
5pattern.lastIndex = 0;
6let match2 = pattern.test(str) ? pattern : /b/g;
7console.log('match2 lastIndex:', match2.lastIndex);
8if (match1.lastIndex !== match2.lastIndex) {
9 throw new Error('lastIndex divergence');
10}
match1 lastIndex: 1
match2 lastIndex: 1
r2-p003 · Hazard 3: Var hoisting and redeclaration
1function test() {
2 for (var i = 0; i < 2; i++) {
3 var x = i ? i : 1;
4 if (i === 0) {
5 var x = 99;
6 }
7 console.log(`i=${i}, x=${x}`);
8 }
9 console.log('final x:', x);
10}
11test();
i=0, x=99
i=1, x=1
final x: 1
r2-p004 · Hazard 4: Precedence change in multiplication
1let b = 0;
2let orig = 5 * (b ? b : 0);
3let fixed = 5 * (b || 0);
4console.log(`b=${b}: orig=${orig}, fixed=${fixed}`);
5if (orig !== fixed) {
6 throw new Error(`Precedence failure: ${orig} !== ${fixed}`);
7}
8b = 2;
9orig = 5 * (b ? b : 0);
10fixed = 5 * (b || 0);
11console.log(`b=${b}: orig=${orig}, fixed=${fixed}`);
12if (orig !== fixed) {
13 throw new Error(`Precedence failure: ${orig} !== ${fixed}`);
14}
b=0: orig=0, fixed=0
b=2: orig=10, fixed=10
r2-p005 · Hazard 5: This binding in extracted method
1const obj = {
2 value: 42,
3 getValue: function() { return this.value; }
4};
5const fn = obj.getValue;
6const x = undefined;
7const result = x ? x : fn.call(obj);
8console.log('result:', result);
9if (result !== 42) {
10 throw new Error(`Expected 42, got ${result}`);
11}
result: 42
r2-p006 · Hazard 6: Null vs undefined in optional chaining
1let obj = { prop: { value: 5 } };
2let maybeNull = null;
3let orig = maybeNull ? maybeNull.prop?.value : 99;
4let fixed = maybeNull ?? maybeNull.prop?.value;
5console.log(`maybeNull=${maybeNull}: orig=${orig}, fixed=${fixed}`);
6if (orig !== fixed) {
7 throw new Error(`Nullish coalescing mismatch: ${orig} !== ${fixed}`);
8}
9maybeNull = undefined;
10orig = maybeNull ? maybeNull.prop?.value : 99;
11fixed = maybeNull ?? maybeNull.prop?.value;
12console.log(`maybeNull=${maybeNull}: orig=${orig}, fixed=${fixed}`);
13if (orig !== fixed) {
14 throw new Error(`Nullish coalescing mismatch: ${orig} !== ${fixed}`);
15}
r2-p007 · Hazard 7: Sparse array hole preservation
1const arr = [1, , 3];
2let sumOrig = 0;
3let sumFixed = 0;
4for (let i = 0; i < arr.length; i++) {
5 const val = arr[i] ? arr[i] : 0;
6 sumOrig += val;
7 const val2 = arr[i] || 0;
8 sumFixed += val2;
9}
10console.log(`sumOrig=${sumOrig}, sumFixed=${sumFixed}`);
11if (sumOrig !== sumFixed) {
12 throw new Error(`Sparse array mismatch: ${sumOrig} !== ${sumFixed}`);
13}
sumOrig=4, sumFixed=4
r2-p008 · Hazard 8: Arguments object interaction
1function test(a, b = 1) {
2 console.log('args.length:', arguments.length);
3 console.log('function.length:', test.length);
4 const x = arguments[0];
5 const orig = x ? x : 2;
6 const fixed = x || 2;
7 console.log(`x=${x}: orig=${orig}, fixed=${fixed}`);
8 if (!Object.is(orig, fixed)) {
9 throw new Error(`Arguments mismatch: ${orig} !== ${fixed}`);
10 }
11 return orig;
12}
13test();
14test(0);
15test(-0);
args.length: 0
function.length: 1
x=undefined: orig=2, fixed=2
args.length: 1
function.length: 1
x=0: orig=2, fixed=2
args.length: 1
function.length: 1
x=0: orig=2, fixed=2