eslint no-undef-init
labelled safe
Analysis Nemotron 3 Super
The rule flags variable declarations that explicitly initialize to undefined.
Fix: Removes the '= undefined' initializer from variable declarators while preserving other parts like commas and spacing.
8 hazards
- For var declarations inside loops, removing the initializer eliminates per-iteration resets to undefined due to hoisting, altering runtime values across iterations.
- When multiple declarators share a statement (e.g., var a = undefined, b = 1;), removing only the undefined initializer may leave trailing commas if not handled properly, risking syntax errors.
- If the undefined initializer is followed by a comment (e.g., var x = undefined /* note */;), the autofix might discard the comment if it's attached to the initializer token rather than the declarator.
- In cases where the variable is redeclared later in the same scope (e.g., var x = undefined; var x;), removing the initializer could cause the second declaration to silently override the first without resetting the value, changing behavior.
- If the initializer uses a non-literal form like void 0 that has side effects in exotic environments (though standardly none), removing it assumes no observable effect, which may not hold in all JS contexts.
- When the declaration is part of a larger expression (e.g., in a sequence or return), stripping the initializer could alter the expression's value or type if the undefined was being used.
- If the code relies on the temporal dead zone behavior (though let/var initialized to undefined doesn't create one), removing the initializer doesn't introduce a TDZ, but the rule doesn't apply to let without initializer anyway—this hazard is low but included for completeness regarding misinterpretation.
- In non-standard or minified code where undefined is rebound (e.g., via with or eval), removing the initializer might not yield the global undefined value, though this is unreliable and discouraged practice.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fired, no fix | Var hoisting and redeclaration interaction | Removing = undefined changes timing of initialization relative to earlier reference under hoisting + redeclaration. |
| r1-p002 | fix ok | Comment discarded when attached to initializer | Autofix removes = undefined but also strips trailing comment if parser attaches it to the initializer token. |
| r1-p003 | silent prediction off | Non-literal void 0 assumed side-effect free | Rule assumes void 0 has no side effects; though standard, exotic engines could trap via Proxy.get on globalThis.undefined. |
| r1-p004 | silent | Temporal dead zone misinterpretation | Rule does not fire on let without initializer; hazard is low but verifies no TDZ introduced by removal. |
| r1-p005 | fix ok | Getter/setter side effects masked | Removing = undefined in init-like context could mask defineProperty side effects if relied upon for timing. |
| r1-p006 | fired, no fix | Arguments and parameter interactions | Removed initializer affects arguments object capture or length in non-strict functions with reuse. |
| r1-p007 | fix ok | Class field evaluation order | Though rule silent on class fields, hazard checks if similar removal would affect super/init timing; proxy via let in constructor. |
| r1-p008 | invalid | Strict vs sloppy mode semantics | In sloppy mode, var a = undefined creates deletable property; after fix, same—but redeclaration + earlier use shows timing delta. |
| r2-p001 | fired, no fix | Multiple declarators sharing statement | When multiple declarators share a statement (e.g., var a = undefined, b = 1;), removing only the undefined initializer may leave trailing commas if not handled properly, risking syntax errors. |
| r2-p002 | invalid | Class fields with static block interaction | class fields, static blocks, private names, super calls |
| r2-p003 | fired, no fix | Redeclaration in same scope overriding initialization | In cases where the variable is redeclared later in the same scope (e.g., var x = undefined; var x;), removing the initializer could cause the second declaration to silently override the first without |
| r2-p004 | fired, no fix | Numeric/string coercion with toString/valueOf | numeric/string coercion: + vs template literal, objects with toString/valueOf, Symbol, BigInt |
| r2-p005 | fired, no fix | Async/await ordering affecting promise resolution | async/await ordering, generators and yield position |
| r2-p006 | fired, no fix | Comment attached to initializer discarded by autofix | If the undefined initializer is followed by a comment (e.g., var x = undefined /* note */;), the autofix might discard the comment if it's attached to the initializer token rather than the declarator. |
| r2-p007 | silent prediction off | Arguments object shadowing broken by init removal | arguments object, function.length, default parameters, rest parameters |
| r2-p008 | invalid | Function declaration in switch case interacting with block-scoped var | function declarations inside blocks, switch cases, labeled statements |
Sources
r1-p001 · Var hoisting and redeclaration interaction
1function f() {
2 console.log(typeof a); // 'undefined'
3 var a;
4 var a = undefined; // removed
5 a = 1;
6 return typeof a;
7}
8console.log(f());
undefined number
r1-p002 · Comment discarded when attached to initializer
1let x = undefined /* keep me */;
2if (typeof x === 'undefined') {
3 console.log('preserve');
4} else {
5 console.log(x);
6}
--- orig.js 2026-10-22 14:20:07.042812805 -0400 +++ fixed.js 2026-10-22 14:20:09.970929972 -0400 @@ -1,4 +1,4 @@ -let x = undefined /* keep me */; +let x /* keep me */; if (typeof x === 'undefined') { console.log('preserve'); } else {
preserve
r1-p003 · Non-literal void 0 assumed side-effect free
1const proto = { get undefined() { throw new Error('trapped') } };
2Object.setPrototypeOf(globalThis, proto);
3try {
4 let y = void 0; // removed
5 console.log('ok', y);
6} catch (e) {
7 console.log(e.name, e.message);
8}
ok undefined
r1-p004 · Temporal dead zone misinterpretation
1{ let z; console.log(typeof z); z = 1; console.log(z); }
undefined 1
r1-p005 · Getter/setter side effects masked
1const o = {};
2Object.defineProperty(o, 'p', {
3 set(v) { console.log('set', v); }
4});
5let o_p = undefined; // removed
6o.p = 42;
--- orig.js 2026-10-22 14:20:07.044812885 -0400 +++ fixed.js 2026-10-22 14:20:10.392946879 -0400 @@ -2,5 +2,5 @@ Object.defineProperty(o, 'p', { set(v) { console.log('set', v); } }); -let o_p = undefined; // removed +let o_p; // removed o.p = 42;
set 42
r1-p006 · Arguments and parameter interactions
1function g(a) {
2 console.log(arguments.length);
3 var a = undefined; // removed
4 return arguments[0];
5}
6console.log(g(1, 2));
2 undefined
r1-p007 · Class field evaluation order
1class Base { constructor() { this.flag = true; } }
2class Derived extends Base {
3 constructor() {
4 super();
5 let x = undefined; // removed
6 console.log(this.flag);
7 this.flag = false;
8 }
9}
10new Derived();
--- orig.js 2026-10-22 14:20:09.252901223 -0400 +++ fixed.js 2026-10-22 14:20:11.925008282 -0400 @@ -2,7 +2,7 @@ class Derived extends Base { constructor() { super(); - let x = undefined; // removed + let x; // removed console.log(this.flag); this.flag = false; }
true
r1-p008 · Strict vs sloppy mode semantics (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-22T18-19-5)
1"use sloppy";
2(function(){
3 console.log(delete a); // false before init
4 var a;
5 var a = undefined; // removed
6 console.log(delete a); // true after
7})();
r2-p001 · Multiple declarators sharing statement
1var x = undefined, y = 1;
2console.log(x === undefined ? 'a' : 'b', y);
3x = 99;
4console.log(x === undefined ? 'a' : 'b', y);
a 1 b 1
r2-p002 · Class fields with static block interaction (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-22T18-19-5)
1class C {
2 static #p;
3 static {
4 try { console.log(#p); } catch(e) { console.log('uninit'); }
5 #p = 42;
6 console.log(#p);
7 }
8}
9new C();
r2-p003 · Redeclaration in same scope overriding initialization
1function f() {
2 var x = undefined;
3 console.log('first:', x === undefined ? 'undef' : x);
4 var x;
5 console.log('second:', x === undefined ? 'undef' : x);
6 x = 5;
7 console.log('third:', x);
8}
9f();
first: undef second: undef third: 5
r2-p004 · Numeric/string coercion with toString/valueOf
1var o = undefined;
2console.log(String(o));
3console.log(typeof o);
4o = { toString: () => 'obj', valueOf: () => 99 };
5console.log(o + '');
6console.log(`${o}`);
undefined undefined 99 obj
r2-p005 · Async/await ordering affecting promise resolution
1async function main() {
2 var p = undefined;
3 console.log('start:', p);
4 p = Promise.resolve(42);
5 console.log('awaited:', await p);
6}
7main().catch(e => console.log(e));
start: undefined awaited: 42
r2-p006 · Comment attached to initializer discarded by autofix
1var z = undefined /* note */;
2console.log(z === undefined ? 'yes' : 'no');
3// comment preserved if fix works
yes
r2-p007 · Arguments object shadowing broken by init removal
1function g(a, b = undefined) {
2 console.log('args.len:', arguments.length);
3 console.log('b:', b === undefined ? 'undef' : b);
4 b = 99;
5 console.log('b after:', b);
6 console.log('arguments[1]:', arguments[1]);
7}
8g(1);
args.len: 1 b: undef b after: 99 arguments[1]: undefined
r2-p008 · Function declaration in switch case interacting with block-scoped var (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-22T18-19-5)
1switch(1) {
2 case 1:
3 var f = undefined;
4 console.log(f === undefined ? 'yes' : 'no');
5 function f() { return 1; }
6 console.log(typeof f);
7 break;
8}