Skip to content

🐞 fix(useForm): mark fields named after Object.prototype members as touched on blur and setValue - #13833

Merged
bluebill1049 merged 4 commits into
react-hook-form:masterfrom
charan-rathore:fix/touched-proto-member-fields
Oct 7, 2026
Merged

bluebill1049 merged 4 commits into
react-hook-form:masterfrom
charan-rathore:fix/touched-proto-member-fields

Conversation

@charan-rathore

Copy link
Copy Markdown
Contributor

Pull Request Template

Proposed Changes

Follow-up to #13832, which fixed dirty-value extraction for a field literally named hasOwnProperty and disclaimed this touched-fields path.

Two places in createFormControl break when a field is named after an Object.prototype function member (hasOwnProperty, toString, valueOf, ...):

  1. Blur crash: delayErrorCallbacks[name] resolves the inherited prototype function for such a name, and invoking it throws inside the blur handler.
  2. Silent miss: updateTouchAndDirty's isPreviousFieldTouched guard reads the same inherited function as truthy, so the field is never marked touched, on both the blur path and setValue(..., { shouldTouch: true }).

Fix: an own-key guard (Object.prototype.hasOwnProperty.call) at the delayErrorCallbacks site, and a typeof === 'function' guard at the touched check, so an inherited function never counts as previously touched.

Tests added: a blur regression test for a hasOwnProperty field, and a setValue shouldTouch test covering hasOwnProperty and toString.

Deliberately out of scope: read-side quirks such as reading formState.touchedFields.hasOwnProperty directly returning the inherited function before the field is touched. Fixing that means guarding the hot-path get() helper and is a perf/bundle-size trade-off for its own discussion.

Verification (run locally on this branch): without the production change the two focused suites fail 3 tests; with it all 115 focused tests pass. Full Jest run: 128 suites, 1514 tests, 26 snapshots green. Prettier clean on the changed files. Not run: typecheck, type tests, build, ESLint, browser E2E, API extractor.

Related: #13832

Fixes # (no issue, follow-up to #13832)

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing tests pass locally with my changes

This change was prepared with AI assistance and verified locally as described above.

Comment thread src/logic/createFormControl.ts Outdated
Comment on lines +649 to +652
if (
!isPreviousFieldTouched ||
typeof isPreviousFieldTouched === 'function'
) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’d prefer not to special-case function values here. Since the issue is inherited Object.prototype members, can we fix the underlying property lookup instead?

@charan-rathore
charan-rathore force-pushed the fix/touched-proto-member-fields branch from 6cdfac5 to 9dae5b5 Compare October 7, 2026 21:12
@charan-rathore

Copy link
Copy Markdown
Contributor Author

Good point, reworked. The blur path now does the property lookup through the library's own own-aware path helper instead:

const isPreviousFieldTouched = has(_formState.touchedFields, name)
  ? get(_formState.touchedFields, name)
  : undefined;

has walks the path checking hasOwnProperty at each step (with the same literal-key fallback as get), so a field named after an Object.prototype member never resolves to the inherited member and no function-value special case is needed. The delayErrorCallbacks lookup already uses an own-property check.

Verified: the new proto-member tests fail without this change and pass with it, full suite green (128 suites, 1514 tests), typecheck/lint/prettier clean.

Comment thread src/logic/createFormControl.ts Resolved
@bluebill1049
bluebill1049 merged commit e76876b into react-hook-form:master Oct 7, 2026
6 checks passed
charan-rathore added a commit to charan-rathore/charan-rathore that referenced this pull request Oct 7, 2026
@charan-rathore
charan-rathore deleted the fix/touched-proto-member-fields branch October 7, 2026 23:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants