Skip to content

Make constructors of internal DOM, MutationObserver, and IntersectionObserver classes throw#57046

Closed
rubennorte wants to merge 1 commit into
facebook:mainfrom
rubennorte:export-D107227212
Closed

Make constructors of internal DOM, MutationObserver, and IntersectionObserver classes throw#57046
rubennorte wants to merge 1 commit into
facebook:mainfrom
rubennorte:export-D107227212

Conversation

@rubennorte
Copy link
Copy Markdown
Contributor

@rubennorte rubennorte commented Jun 2, 2026

Summary:
Several Web API classes exposed globally by React Native are not meant to be constructed from userland. They fall into two groups:

  • Classes whose web spec constructors are illegal regardless of platform: Node, Element, CharacterData, HTMLCollection, NodeList, DOMRectList, IntersectionObserverEntry, MutationRecord. The web platform itself throws an "Illegal constructor" TypeError for these.
  • Classes whose web spec constructors are public, but whose React Native implementations cannot be constructed from userland because nodes cannot be imperatively created in React Native — only React can create them during rendering. These are Document, Text, and HTMLElement.

Apply the same _public pattern already in use under setUpPerformanceModern to these classes: export a constructor stub that throws a TypeError, with its prototype aliased to the real class so that instanceof checks against the global still work. Internal code continues to use the real class via the default export.

For the first group the thrown message follows the web convention, e.g.:

TypeError: Failed to construct 'Node': Illegal constructor

For the second group the message clarifies the React-Native-specific reason, e.g.:

TypeError: Failed to construct 'Document': Nodes cannot be imperatively created in React Native

The following classes get a _public export and are now polyfilled through it in their corresponding setup file:

  • setUpDOM: DOMRectList, HTMLCollection, NodeList, Node (ReadOnlyNode), Document (ReactNativeDocument), CharacterData (ReadOnlyCharacterData), Text (ReadOnlyText), Element (ReadOnlyElement), HTMLElement (ReactNativeElement).
  • setUpMutationObserver: MutationRecord.
  • setUpIntersectionObserver: IntersectionObserverEntry (also newly added to the setup file — it was not being exposed globally before).

For Node, the public stub also copies the static node-type and document-position constants (ELEMENT_NODE, TEXT_NODE, DOCUMENT_POSITION_*, etc.) so that consumers can keep reading them from the global (Node.ELEMENT_NODE, …).

Classes whose web-spec constructors are legitimately public (DOMRect, DOMRectReadOnly, Event, EventTarget, CustomEvent, MutationObserver, IntersectionObserver) are unchanged.

For the three collection classes whose public Flow types live in a .js.flow declaration file (DOMRectList, HTMLCollection, NodeList), the new _public export is also declared in the .js.flow companion so Flow can see it.

Changelog:
[General][Changed] - Throw "Illegal constructor" TypeError when constructing Node from JavaScript
[General][Changed] - Throw "Illegal constructor" TypeError when constructing Element from JavaScript
[General][Changed] - Throw "Illegal constructor" TypeError when constructing CharacterData from JavaScript
[General][Changed] - Throw "Illegal constructor" TypeError when constructing HTMLCollection from JavaScript
[General][Changed] - Throw "Illegal constructor" TypeError when constructing NodeList from JavaScript
[General][Changed] - Throw "Illegal constructor" TypeError when constructing DOMRectList from JavaScript
[General][Changed] - Throw "Illegal constructor" TypeError when constructing IntersectionObserverEntry from JavaScript
[General][Changed] - Throw "Illegal constructor" TypeError when constructing MutationRecord from JavaScript
[General][Changed] - Throw "Nodes cannot be imperatively created in React Native" TypeError when constructing Document from JavaScript
[General][Changed] - Throw "Nodes cannot be imperatively created in React Native" TypeError when constructing Text from JavaScript
[General][Changed] - Throw "Nodes cannot be imperatively created in React Native" TypeError when constructing HTMLElement from JavaScript
[General][Added] - Expose IntersectionObserverEntry as a global

Reviewed By: huntie

Differential Revision: D107227212

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jun 2, 2026
@facebook-github-tools facebook-github-tools Bot added p: Facebook Partner: Facebook Partner labels Jun 2, 2026
@meta-codesync
Copy link
Copy Markdown

meta-codesync Bot commented Jun 2, 2026

@rubennorte has exported this pull request. If you are a Meta employee, you can view the originating Diff in D107227212.

rubennorte added a commit to rubennorte/react-native that referenced this pull request Jun 2, 2026
…Observer classes throw (facebook#57046)

Summary:
Pull Request resolved: facebook#57046

Several Web API classes exposed globally by React Native are not meant to be constructed from userland — either because they correspond to web spec interfaces whose constructors are illegal (e.g. `Node`, `Element`, `HTMLCollection`, `NodeList`, `DOMRectList`, `IntersectionObserverEntry`, `MutationRecord`), or because their React Native implementations take internal arguments that callers cannot meaningfully supply (e.g. `Document`, `Text`, `CharacterData`, `HTMLElement`).

Apply the same `_public` pattern already in use under `setUpPerformanceModern` to these classes: export a constructor stub that throws `TypeError: Failed to construct '<Name>': Illegal constructor`, with its `prototype` aliased to the real class so that `instanceof` checks against the global still work. Internal code continues to use the real class via the default export.

The following classes get a `_public` export and are now polyfilled through it in their corresponding setup file:

- `setUpDOM`: `DOMRectList`, `HTMLCollection`, `NodeList`, `Node` (`ReadOnlyNode`), `Document` (`ReactNativeDocument`), `CharacterData` (`ReadOnlyCharacterData`), `Text` (`ReadOnlyText`), `Element` (`ReadOnlyElement`), `HTMLElement` (`ReactNativeElement`).
- `setUpMutationObserver`: `MutationRecord`.
- `setUpIntersectionObserver`: `IntersectionObserverEntry` (also newly added to the setup file — it was not being exposed globally before).

For `Node`, the public stub also copies the static node-type and document-position constants (`ELEMENT_NODE`, `TEXT_NODE`, `DOCUMENT_POSITION_*`, etc.) so that consumers can keep reading them from the global (`Node.ELEMENT_NODE`, …).

Classes whose web-spec constructors are legitimately public (`DOMRect`, `DOMRectReadOnly`, `Event`, `EventTarget`, `CustomEvent`, `MutationObserver`, `IntersectionObserver`) are unchanged.

For the three collection classes whose public Flow types live in a `.js.flow` declaration file (`DOMRectList`, `HTMLCollection`, `NodeList`), the new `_public` export is also declared in the `.js.flow` companion so Flow can see it.

Changelog:
[General][Fixed] - Throw "Illegal constructor" when constructing `Node`, `Document`, `Element`, `HTMLElement`, `CharacterData`, `Text`, `HTMLCollection`, `NodeList`, `DOMRectList`, `MutationRecord`, and `IntersectionObserverEntry` from JavaScript.

Reviewed By: huntie

Differential Revision: D107227212
@meta-codesync meta-codesync Bot changed the title Make constructors of internal DOM, MutationObserver, and IntersectionObserver classes throw Make constructors of internal DOM, MutationObserver, and IntersectionObserver classes throw (#57046) Jun 2, 2026
@rubennorte rubennorte force-pushed the export-D107227212 branch from 84775c8 to 33b8d6a Compare June 2, 2026 13:59
…Observer classes throw

Summary:
Several Web API classes exposed globally by React Native are not meant to be constructed from userland. They fall into two groups:

- Classes whose web spec constructors are illegal regardless of platform: `Node`, `Element`, `CharacterData`, `HTMLCollection`, `NodeList`, `DOMRectList`, `IntersectionObserverEntry`, `MutationRecord`. The web platform itself throws an "Illegal constructor" `TypeError` for these.
- Classes whose web spec constructors are public, but whose React Native implementations cannot be constructed from userland because nodes cannot be imperatively created in React Native — only React can create them during rendering. These are `Document`, `Text`, and `HTMLElement`.

Apply the same `_public` pattern already in use under `setUpPerformanceModern` to these classes: export a constructor stub that throws a `TypeError`, with its `prototype` aliased to the real class so that `instanceof` checks against the global still work. Internal code continues to use the real class via the default export.

For the first group the thrown message follows the web convention, e.g.:

  TypeError: Failed to construct 'Node': Illegal constructor

For the second group the message clarifies the React-Native-specific reason, e.g.:

  TypeError: Failed to construct 'Document': Nodes cannot be imperatively created in React Native

The following classes get a `_public` export and are now polyfilled through it in their corresponding setup file:

- `setUpDOM`: `DOMRectList`, `HTMLCollection`, `NodeList`, `Node` (`ReadOnlyNode`), `Document` (`ReactNativeDocument`), `CharacterData` (`ReadOnlyCharacterData`), `Text` (`ReadOnlyText`), `Element` (`ReadOnlyElement`), `HTMLElement` (`ReactNativeElement`).
- `setUpMutationObserver`: `MutationRecord`.
- `setUpIntersectionObserver`: `IntersectionObserverEntry` (also newly added to the setup file — it was not being exposed globally before).

For `Node`, the public stub also copies the static node-type and document-position constants (`ELEMENT_NODE`, `TEXT_NODE`, `DOCUMENT_POSITION_*`, etc.) so that consumers can keep reading them from the global (`Node.ELEMENT_NODE`, …).

Classes whose web-spec constructors are legitimately public (`DOMRect`, `DOMRectReadOnly`, `Event`, `EventTarget`, `CustomEvent`, `MutationObserver`, `IntersectionObserver`) are unchanged.

For the three collection classes whose public Flow types live in a `.js.flow` declaration file (`DOMRectList`, `HTMLCollection`, `NodeList`), the new `_public` export is also declared in the `.js.flow` companion so Flow can see it.

Changelog:
[General][Changed] - Throw "Illegal constructor" `TypeError` when constructing `Node` from JavaScript
[General][Changed] - Throw "Illegal constructor" `TypeError` when constructing `Element` from JavaScript
[General][Changed] - Throw "Illegal constructor" `TypeError` when constructing `CharacterData` from JavaScript
[General][Changed] - Throw "Illegal constructor" `TypeError` when constructing `HTMLCollection` from JavaScript
[General][Changed] - Throw "Illegal constructor" `TypeError` when constructing `NodeList` from JavaScript
[General][Changed] - Throw "Illegal constructor" `TypeError` when constructing `DOMRectList` from JavaScript
[General][Changed] - Throw "Illegal constructor" `TypeError` when constructing `IntersectionObserverEntry` from JavaScript
[General][Changed] - Throw "Illegal constructor" `TypeError` when constructing `MutationRecord` from JavaScript
[General][Changed] - Throw "Nodes cannot be imperatively created in React Native" `TypeError` when constructing `Document` from JavaScript
[General][Changed] - Throw "Nodes cannot be imperatively created in React Native" `TypeError` when constructing `Text` from JavaScript
[General][Changed] - Throw "Nodes cannot be imperatively created in React Native" `TypeError` when constructing `HTMLElement` from JavaScript
[General][Added] - Expose `IntersectionObserverEntry` as a global

Reviewed By: huntie

Differential Revision: D107227212
@meta-codesync meta-codesync Bot changed the title Make constructors of internal DOM, MutationObserver, and IntersectionObserver classes throw (#57046) Make constructors of internal DOM, MutationObserver, and IntersectionObserver classes throw Jun 2, 2026
@rubennorte rubennorte force-pushed the export-D107227212 branch from 33b8d6a to fbc9087 Compare June 2, 2026 16:10
@meta-codesync meta-codesync Bot closed this in 4deb32a Jun 2, 2026
@facebook-github-tools facebook-github-tools Bot added the Merged This PR has been merged. label Jun 2, 2026
@meta-codesync
Copy link
Copy Markdown

meta-codesync Bot commented Jun 2, 2026

This pull request has been merged in 4deb32a.

@react-native-bot
Copy link
Copy Markdown
Collaborator

This pull request was successfully merged by @rubennorte in 4deb32a

When will my fix make it into a release? | How to file a pick request?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. fb-exported Merged This PR has been merged. meta-exported p: Facebook Partner: Facebook Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants