fixhunt

eslint prefer-object-has-own

labelled safe
Runs / 2026-10-22T18-28-21-081Z-4isd-eslint-prefer-object-has-owneslint 9.39.52026-10-22 18:28 UTC8 programs × 2 round(s)16 programs, 16 fired, 16 fixed, 0 findings, 0 rejectedmodel cost $0.0035

Analysis Nemotron 3 Super

The rule flags calls to `Object.prototype.hasOwnProperty.call()` (or variants using `Object.hasOwnProperty.call`, object literals, etc.) and suggests replacing them with `Object.hasOwn()`.

Fix: Replace `X.hasOwnProperty.call(obj, prop)` where X is `Object.prototype`, `Object`, or `{}` with `Object.hasOwn(obj, prop)`.

11 hazards
  • If `Object.hasOwn` is shadowed by a local variable in scope, the rewrite will refer to that variable instead of the global built-in, changing behavior.
  • If the original code relied on `Object.prototype.hasOwnProperty.call` being a specific function object (e.g., for equality checks or `typeof`), replacing it with `Object.hasOwn` may break such checks.
  • If the `obj` or `prop` expressions have side effects, the rewrite preserves their evaluation order only if the autotool keeps the same argument order—which it does—but any tool that reorders arguments would introduce a hazard; however, the rule’s fix does not reorder, so this is not a hazard of the fix itself.
  • If `Object` is rebound (e.g., `let Object = null;`), then `Object.hasOwn` will throw or behave incorrectly, whereas the original `Object.prototype.hasOwnProperty.call` might still work if `Object.prototype` is unaffected—but this is a preexisting issue, not introduced by the fix.
  • If the code is in a context where `Object.hasOwn` is not supported (e.g., older engines), the rewrite will cause a runtime error, while the original code would have worked—this is a versioning hazard, but the rule should only be used where ES2022+ is supported.
  • If the call is part of a larger expression and the autofix removes parentheses implicitly relied on for grouping, it could change precedence—but the fix replaces a full CallExpression with another, preserving expression structure, so this is unlikely.
  • If the original code had trailing comments on the same line after the semicolon, some autofix implementations might incorrectly discard them if they replace the whole statement without preserving trailing comments.
  • If the original code used a computed property access like `obj[expr]` and the autofix does not preserve the exact spacing or formatting, it could affect readability but not behavior—this is not a behavioral hazard.
  • If the `obj` expression is `undefined` or `null`, both `Object.prototype.hasOwnProperty.call` and `Object.hasOwn` throw the same TypeError, so no behavioral change occurs.
  • If the original code was written as `(Object.prototype.hasOwnProperty).call(obj, prop)` and the rule somehow misfires, but the rule does not flag this form, so it’s not relevant.
  • If the codebase uses a polyfill for `Object.hasOwn` that behaves differently from the native version (e.g., treats `-0` and `0` differently), then the rewrite might change behavior relative to expectations—but this depends on the polyfill, not the fix itself.

Programs

idresulttitlehazard
r1-p001fix okSide-effect preservation checkIf arguments have side effects, the fix must preserve evaluation order.
r1-p002fix okStrict vs sloppy mode interactionIn strict mode, hasOwnProperty on null/undefined throws; fix behaves same but must not alter this-binding.
r1-p003fix okAsync/await ordering with generator yieldFix must not interfere with await/yield evaluation order in async generators.
r1-p004fix ok prediction offES2022+ versioning hazardRewrite fails in pre-ES2022 environments where Object.hasOwn is missing.
r1-p005fix okLabel/break/finally control flowFix inside labeled block must not break break/continue/finally semantics.
r1-p006fix okRegex lastIndex interaction with global flagArguments involving regex.lastIndex with /g must retain evaluation order.
r1-p007fix okTrailing comment preservationAutofix may discard trailing comments on same line after statement.
r1-p008fix okClass fields and static blocks interactionFix in static block must not interfere with class field initialization or super.
r2-p001fix okNull/undefined distinction with optional chaining short-circuitnull/undefined distinction, optional chaining short-circuit, nullish vs falsy
r2-p002fix okNull/undefined throws same error in both versionsStrict vs sloppy mode interaction (In strict mode, hasOwnProperty on null/undefined throws; fix behaves same but mu)
r2-p003fix okParentheses reliance in larger expression (edge case testing precedence)If the call is part of a larger expression and the autofix removes parentheses implicitly relied on for grouping, it could change precedence—but the fix replaces a full CallExpression with another, pr
r2-p004fix okFunction declarations inside blocks, switch cases, labeled statementsfunction declarations inside blocks, switch cases, labeled statements
r2-p005fix okVar hoisting and re-declaration inside loops or after usevar hoisting and re-declaration inside loops or after use
r2-p006fix okES2022+ versioning hazard: Object.hasOwn missing in older envIf the code is in a context where `Object.hasOwn` is not supported (e.g., older engines), the rewrite will cause a runtime error, while the original code would have worked—this is a versioning hazard,
r2-p007fix okTrailing comment preservation on same line after statementIf the original code had trailing comments on the same line after the semicolon, some autofix implementations might incorrectly discard them if they replace the whole statement without preserving trai
r2-p008fix okGetters, setters and Object.defineProperty side effectsgetters, setters and Object.defineProperty side effects

Sources

r1-p001 · Side-effect preservation check
1let a = 0, b = 0;
2function next() { return ++a; }
3function val() { return ++b; }
4console.log(Object.prototype.hasOwnProperty.call({ [val()]: 'x' }, next()) ? 'yes' : 'no');
5console.log(`a=${a} b=${b}`);
--- orig.js	2026-10-22 14:28:30.490417742 -0400
+++ fixed.js	2026-10-22 14:28:34.966379683 -0400
@@ -1,5 +1,5 @@
 let a = 0, b = 0;
 function next() { return ++a; }
 function val() { return ++b; }
-console.log(Object.prototype.hasOwnProperty.call({ [val()]: 'x' }, next()) ? 'yes' : 'no');
+console.log(Object.hasOwn({ [val()]: 'x' }, next()) ? 'yes' : 'no');
 console.log(`a=${a} b=${b}`);
yes
a=1 b=1
r1-p002 · Strict vs sloppy mode interaction
1"use strict";
2try {
3 console.log(Object.prototype.hasOwnProperty.call(null, 'x'));
4} catch (e) {
5 console.log(e.name);
6}
7try {
8 console.log(Object.hasOwn(null, 'x'));
9} catch (e) {
10 console.log(e.name);
11}
--- orig.js	2026-10-22 14:28:30.491417733 -0400
+++ fixed.js	2026-10-22 14:28:33.180394650 -0400
@@ -1,6 +1,6 @@
 "use strict";
 try {
-  console.log(Object.prototype.hasOwnProperty.call(null, 'x'));
+  console.log(Object.hasOwn(null, 'x'));
 } catch (e) {
   console.log(e.name);
 }
TypeError
TypeError
r1-p003 · Async/await ordering with generator yield
1async function* gen() {
2 let obj = {};
3 obj[await Promise.resolve('key')] = 1;
4 if (Object.prototype.hasOwnProperty.call(obj, await Promise.resolve('key'))) {
5 yield 1;
6 }
7}
8gen().next().then(({value}) => console.log(value));
--- orig.js	2026-10-22 14:28:30.492417725 -0400
+++ fixed.js	2026-10-22 14:28:35.010379316 -0400
@@ -1,7 +1,7 @@
 async function* gen() {
   let obj = {};
   obj[await Promise.resolve('key')] = 1;
-  if (Object.prototype.hasOwnProperty.call(obj, await Promise.resolve('key'))) {
+  if (Object.hasOwn(obj, await Promise.resolve('key'))) {
     yield 1;
   }
 }
1
r1-p004 · ES2022+ versioning hazard
1let obj = { a: 1 };
2let result = typeof Object.hasOwn === 'function'
3 ? Object.hasOwn(obj, 'a')
4 : Object.prototype.hasOwnProperty.call(obj, 'a');
5console.log(result); // prints true only if polyfilled or modern
--- orig.js	2026-10-22 14:28:30.493417716 -0400
+++ fixed.js	2026-10-22 14:28:34.948379833 -0400
@@ -1,5 +1,5 @@
 let obj = { a: 1 };
 let result = typeof Object.hasOwn === 'function'
   ? Object.hasOwn(obj, 'a')
-  : Object.prototype.hasOwnProperty.call(obj, 'a');
+  : Object.hasOwn(obj, 'a');
 console.log(result); // prints true only if polyfilled or modern
true
r1-p005 · Label/break/finally control flow
1outer: {
2 let obj = { x: 1 };
3 if (Object.prototype.hasOwnProperty.call(obj, 'x')) {
4 console.log('found');
5 break outer;
6 }
7 console.log('missed');
8}
9console.log('done');
--- orig.js	2026-10-22 14:28:30.493417716 -0400
+++ fixed.js	2026-10-22 14:28:33.760389761 -0400
@@ -1,6 +1,6 @@
 outer: {
   let obj = { x: 1 };
-  if (Object.prototype.hasOwnProperty.call(obj, 'x')) {
+  if (Object.hasOwn(obj, 'x')) {
     console.log('found');
     break outer;
   }
found
done
r1-p006 · Regex lastIndex interaction with global flag
1let obj = {};
2let re = /a/g;
3re.lastIndex = 0;
4obj[re.exec('ba')] = true; // sets obj['a'] = true
5if (Object.prototype.hasOwnProperty.call(obj, re.exec('ba')[0])) {
6 console.log('has');
7} else {
8 console.log('missing');
9}
10console.log(re.lastIndex); // should be 2 if two execs ran
--- orig.js	2026-10-22 14:28:30.494417707 -0400
+++ fixed.js	2026-10-22 14:28:35.028379168 -0400
@@ -2,7 +2,7 @@
 let re = /a/g;
 re.lastIndex = 0;
 obj[re.exec('ba')] = true; // sets obj['a'] = true
-if (Object.prototype.hasOwnProperty.call(obj, re.exec('ba')[0])) {
+if (Object.hasOwn(obj, re.exec('ba')[0])) {
   console.log('has');
 } else {
   console.log('missing');
r1-p007 · Trailing comment preservation
1let obj = { prop: 42 };
2let has = Object.prototype.hasOwnProperty.call(obj, 'prop'); // keep this comment
3console.log(has); // should print true
4// Expected output: true then comment about keeping
--- orig.js	2026-10-22 14:28:34.845380691 -0400
+++ fixed.js	2026-10-22 14:28:36.894363861 -0400
@@ -1,4 +1,4 @@
 let obj = { prop: 42 };
-let has = Object.prototype.hasOwnProperty.call(obj, 'prop'); // keep this comment
+let has = Object.hasOwn(obj, 'prop'); // keep this comment
 console.log(has); // should print true
 // Expected output: true then comment about keeping
true
r1-p008 · Class fields and static blocks interaction
1class C {
2 static staticField;
3 static {
4 let tmp = { prop: 1 };
5 C.staticField = Object.prototype.hasOwnProperty.call(tmp, 'prop') ? 'yes' : 'no';
6 }
7 instanceField = Object.hasOwn(C.prototype, 'instanceField') ? 1 : 0;
8}
9console.log(C.staticField);
10console.log(new C().instanceField);
--- orig.js	2026-10-22 14:28:34.880380400 -0400
+++ fixed.js	2026-10-22 14:28:38.593350204 -0400
@@ -2,7 +2,7 @@
   static staticField;
   static {
     let tmp = { prop: 1 };
-    C.staticField = Object.prototype.hasOwnProperty.call(tmp, 'prop') ? 'yes' : 'no';
+    C.staticField = Object.hasOwn(tmp, 'prop') ? 'yes' : 'no';
   }
   instanceField = Object.hasOwn(C.prototype, 'instanceField') ? 1 : 0;
 }
yes
0
r2-p001 · Null/undefined distinction with optional chaining short-circuit
1let o = {a: 1}; let x;
2function getObj() { return x; }
3console.log(getObj()?.a ?? 'missing');
4if (Object.prototype.hasOwnProperty.call(getObj(), 'a')) {
5 console.log('has own');
6} else {
7 console.log('does not have own');
8}
--- orig.js	2026-10-22 14:28:44.968301252 -0400
+++ fixed.js	2026-10-22 14:28:49.334269846 -0400
@@ -1,7 +1,7 @@
 let o = {a: 1}; let x;
 function getObj() { return x; }
 console.log(getObj()?.a ?? 'missing');
-if (Object.prototype.hasOwnProperty.call(getObj(), 'a')) {
+if (Object.hasOwn(getObj(), 'a')) {
   console.log('has own');
 } else {
   console.log('does not have own');
missing
r2-p002 · Null/undefined throws same error in both versions
1'use strict';
2try {
3 Object.prototype.hasOwnProperty.call(null, 'x');
4} catch (e) {
5 console.log(e.name + ': ' + e.message);
6}
7try {
8 Object.hasOwn(null, 'x');
9} catch (e) {
10 console.log(e.name + ': ' + e.message);
11}
--- orig.js	2026-10-22 14:28:44.969301245 -0400
+++ fixed.js	2026-10-22 14:28:49.266270321 -0400
@@ -1,6 +1,6 @@
 'use strict';
 try {
-  Object.prototype.hasOwnProperty.call(null, 'x');
+  Object.hasOwn(null, 'x');
 } catch (e) {
   console.log(e.name + ': ' + e.message);
 }
TypeError: Cannot convert undefined or null to object
TypeError: Cannot convert undefined or null to object
r2-p003 · Parentheses reliance in larger expression (edge case testing precedence)
1let o = {a: 1};
2let result = !Object.prototype.hasOwnProperty.call(o, 'a') && 0;
3console.log('Result:', result);
4result = !Object.hasOwn(o, 'a') && 0;
5console.log('Result after fix:', result);
--- orig.js	2026-10-22 14:28:44.970301237 -0400
+++ fixed.js	2026-10-22 14:28:48.139278270 -0400
@@ -1,5 +1,5 @@
 let o = {a: 1};
-let result = !Object.prototype.hasOwnProperty.call(o, 'a') && 0;
+let result = !Object.hasOwn(o, 'a') && 0;
 console.log('Result:', result);
 result = !Object.hasOwn(o, 'a') && 0;
 console.log('Result after fix:', result);
Result: false
Result after fix: false
r2-p004 · Function declarations inside blocks, switch cases, labeled statements
1function test() {
2 let o = {x: 1};
3 switch (o.x) {
4 case 1:
5 function inner() { return Object.prototype.hasOwnProperty.call(o, 'x'); }
6 console.log(inner());
7 break;
8 }
9 label: {
10 if (Object.prototype.hasOwnProperty.call(o, 'x')) {
11 break label;
12 }
13 console.log('should not reach');
14 }
15}
16test();
--- orig.js	2026-10-22 14:28:44.970301237 -0400
+++ fixed.js	2026-10-22 14:28:49.287270174 -0400
@@ -2,12 +2,12 @@
   let o = {x: 1};
   switch (o.x) {
     case 1:
-      function inner() { return Object.prototype.hasOwnProperty.call(o, 'x'); }
+      function inner() { return Object.hasOwn(o, 'x'); }
       console.log(inner());
       break;
   }
   label: {
-    if (Object.prototype.hasOwnProperty.call(o, 'x')) {
+    if (Object.hasOwn(o, 'x')) {
       break label;
     }
     console.log('should not reach');
true
r2-p005 · Var hoisting and re-declaration inside loops or after use
1for (var i = 0; i < 2; i++) {
2 var o = {a: i};
3 if (Object.prototype.hasOwnProperty.call(o, 'a')) {
4 console.log('loop', i, 'has a');
5 }
6}
7console.log('o after loop:', typeof o);
8if (Object.prototype.hasOwnProperty.call(o, 'a')) {
9 console.log('o has a');
10} else {
11 console.log('o does not have a');
12}
--- orig.js	2026-10-22 14:28:44.970301237 -0400
+++ fixed.js	2026-10-22 14:28:49.312269999 -0400
@@ -1,11 +1,11 @@
 for (var i = 0; i < 2; i++) {
   var o = {a: i};
-  if (Object.prototype.hasOwnProperty.call(o, 'a')) {
+  if (Object.hasOwn(o, 'a')) {
     console.log('loop', i, 'has a');
   }
 }
 console.log('o after loop:', typeof o);
-if (Object.prototype.hasOwnProperty.call(o, 'a')) {
+if (Object.hasOwn(o, 'a')) {
   console.log('o has a');
 } else {
   console.log('o does not have a');
loop 0 has a
loop 1 has a
o after loop: object
o has a
r2-p006 · ES2022+ versioning hazard: Object.hasOwn missing in older env
1let o = {a: 1};
2if (typeof Object.hasOwn !== 'function') {
3 console.log('Object.hasOwn not available, simulating old engine');
4 // We still call the original to show it works
5 console.log(Object.prototype.hasOwnProperty.call(o, 'a'));
6} else {
7 console.log(Object.prototype.hasOwnProperty.call(o, 'a'));
8 console.log(Object.hasOwn(o, 'a'));
9}
--- orig.js	2026-10-22 14:28:44.971301230 -0400
+++ fixed.js	2026-10-22 14:28:47.051286053 -0400
@@ -2,8 +2,8 @@
 if (typeof Object.hasOwn !== 'function') {
   console.log('Object.hasOwn not available, simulating old engine');
   // We still call the original to show it works
-  console.log(Object.prototype.hasOwnProperty.call(o, 'a'));
+  console.log(Object.hasOwn(o, 'a'));
 } else {
-  console.log(Object.prototype.hasOwnProperty.call(o, 'a'));
+  console.log(Object.hasOwn(o, 'a'));
   console.log(Object.hasOwn(o, 'a'));
 }
true
true
r2-p007 · Trailing comment preservation on same line after statement
1let o = {a: 1};
2if (Object.prototype.hasOwnProperty.call(o, 'a')) { // check if a exists
3 console.log('yes');
4} // end if
5console.log('done');
--- orig.js	2026-10-22 14:28:49.221270635 -0400
+++ fixed.js	2026-10-22 14:28:51.297256273 -0400
@@ -1,5 +1,5 @@
 let o = {a: 1};
-if (Object.prototype.hasOwnProperty.call(o, 'a')) { // check if a exists
+if (Object.hasOwn(o, 'a')) { // check if a exists
   console.log('yes');
 } // end if
 console.log('done');
yes
done
r2-p008 · Getters, setters and Object.defineProperty side effects
1let obj = {};
2let val = 42;
3Object.defineProperty(obj, 'prop', {
4 get() { console.log('getter called'); return val; },
5 enumerable: true,
6 configurable: true
7});
8console.log('Before check, val =', val);
9if (Object.prototype.hasOwnProperty.call(obj, 'prop')) {
10 console.log('Has own prop');
11}
12console.log('After check, val =', val);
--- orig.js	2026-10-22 14:28:49.738267023 -0400
+++ fixed.js	2026-10-22 14:28:52.357249087 -0400
@@ -6,7 +6,7 @@
   configurable: true
 });
 console.log('Before check, val =', val);
-if (Object.prototype.hasOwnProperty.call(obj, 'prop')) {
+if (Object.hasOwn(obj, 'prop')) {
   console.log('Has own prop');
 }
 console.log('After check, val =', val);
Before check, val = 42
Has own prop
After check, val = 42