Repository: facebook/react
Pull request: Root import types from react-native in ReactNativeTypes

<!--
  Thanks for submitting a pull request!
  We appreciate you spending the time to work on these changes. Please provide enough information so that others can review your pull request. The three fields below are mandatory.

  Before submitting a pull request, please make sure the following is done:

  1. Fork [the repository](https://github.com/facebook/react) and create your branch from `main`.
  2. Run `yarn` in the repository root.
  3. If you've fixed a bug or added code that should be tested, add tests!
  4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch TestName` is helpful in development.
  5. Run `yarn test --prod` to test in the production environment. It supports the same options as `yarn test`.
  6. If you need a debugger, run `yarn test --debug --watch TestName`, open `chrome://inspect`, and press "Inspect".
  7. Format your code with [prettier](https://github.com/prettier/prettier) (`yarn prettier`).
  8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only check changed files.
  9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
  10. If you haven't already, complete the CLA.

  Learn more about contributing: https://reactjs.org/docs/how-to-contribute.html
-->

## Summary

<!--
 Explain the **motivation** for making this change. What existing problem does the pull request solve?
-->

This PR migrates deep import from react-native to the root import. The motivation behind this is that the newly introduced package exports in react native are more strict, and this import breaks type resolution for `ReactNativePrivateInterface`.

After adding `HostInstance`, `PublicTextInstance`, and `PublicRootInstance` to the `react-native` module, CIs failed due to different opaque types in `react-native` and `ReactNativePrivateInterface`. Moving their declarations to the global scope fixed the issue. It is not entirely possible to migrate `react-native-renderer` to root imports, as not all used identifiers are root exported in `react-native`.

Imported `react` types are changed to be used under the `React` namespace. This is required for Flow tooling to translate them into TypeScript equivalents correctly.

## How did you test this change?

Signals, react-native main

<!--
  Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes the user interface.
  How exactly did you verify that your PR solves the issue you wanted to solve?
  If you leave this empty, your PR will very likely be closed.
-->


Changed files:
filename: packages/react-native-renderer/src/ReactNativeTypes.js
patch: @@ -9,22 +9,18 @@
  * @flow strict
  */
 
-import type {
-  Component as ReactComponent,
-  ElementRef,
-  ElementType,
-  MixedElement,
-} from 'react';
 import type {
   // $FlowFixMe[nonstrict-import] TODO(@rubennorte)
-  MeasureOnSuccessCallback,
+  HostInstance as PublicInstance,
   // $FlowFixMe[nonstrict-import] TODO(@rubennorte)
-  PublicInstance,
+  MeasureOnSuccessCallback,
   // $FlowFixMe[nonstrict-import] TODO(@rubennorte)
   PublicRootInstance,
   // $FlowFixMe[nonstrict-import] TODO(@rubennorte)
   PublicTextInstance,
-} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
+} from 'react-native';
+
+import * as React from 'react';
 
 export type AttributeType<T, V> =
   | true
@@ -96,8 +92,8 @@ type InspectorDataProps = $ReadOnly<{
 }>;
 
 type InspectorDataGetter = (
-  <TElementType: ElementType>(
-    componentOrHandle: ElementRef<TElementType> | number,
+  <TElementType: React.ElementType>(
+    componentOrHandle: React.ElementRef<TElementType> | number,
   ) => ?number,
 ) => $ReadOnly<{
   measure: (callback: MeasureOnSuccessCallback) => void,
@@ -140,7 +136,7 @@ export type RenderRootOptions = {
       +componentStack?: ?string,
       // $FlowFixMe[unclear-type] unknown props and state.
       // $FlowFixMe[value-as-type] Component in react repo is any-typed, but it will be well typed externally.
-      +errorBoundary?: ?ReactComponent<any, any>,
+      +errorBoundary?: ?React.Component<any, any>,
     },
   ) => void,
   onRecoverableError?: (
@@ -154,11 +150,11 @@ export type RenderRootOptions = {
  * Provide minimal Flow typing for the high-level RN API and call it a day.
  */
 export type ReactNativeType = {
-  findHostInstance_DEPRECATED<TElementType: ElementType>(
-    componentOrHandle: ?(ElementRef<TElementType> | number),
+  findHostInstance_DEPRECATED<TElementType: React.ElementType>(
+    componentOrHandle: ?(React.ElementRef<TElementType> | number),
   ): ?PublicInstance,
-  findNodeHandle<TElementType: ElementType>(
-    componentOrHandle: ?(ElementRef<TElementType> | number),
+  findNodeHandle<TElementType: React.ElementType>(
+    componentOrHandle: ?(React.ElementRef<TElementType> | number),
   ): ?number,
   isChildPublicInstance(parent: PublicInstance, child: PublicInstance): boolean,
   dispatchCommand(
@@ -168,11 +164,11 @@ export type ReactNativeType = {
   ): void,
   sendAccessibilityEvent(handle: PublicInstance, eventType: string): void,
   render(
-    element: MixedElement,
+    element: React.MixedElement,
     containerTag: number,
     callback: ?() => void,
     options: ?RenderRootOptions,
-  ): ?ElementRef<ElementType>,
+  ): ?React.ElementRef<React.ElementType>,
   unmountComponentAtNode(containerTag: number): void,
   unmountComponentAtNodeAndRemoveContainer(containerTag: number): void,
   +unstable_batchedUpdates: <T>(fn: (T) => void, bookkeeping: T) => void,
@@ -183,11 +179,11 @@ export opaque type Node = mixed;
 export opaque type InternalInstanceHandle = mixed;
 
 export type ReactFabricType = {
-  findHostInstance_DEPRECATED<TElementType: ElementType>(
-    componentOrHandle: ?(ElementRef<TElementType> | number),
+  findHostInstance_DEPRECATED<TElementType: React.ElementType>(
+    componentOrHandle: ?(React.ElementRef<TElementType> | number),
   ): ?PublicInstance,
-  findNodeHandle<TElementType: ElementType>(
-    componentOrHandle: ?(ElementRef<TElementType> | number),
+  findNodeHandle<TElementType: React.ElementType>(
+    componentOrHandle: ?(React.ElementRef<TElementType> | number),
   ): ?number,
   dispatchCommand(
     handle: PublicInstance,
@@ -197,12 +193,12 @@ export type ReactFabricType = {
   isChildPublicInstance(parent: PublicInstance, child: PublicInstance): boolean,
   sendAccessibilityEvent(handle: PublicInstance, eventType: string): void,
   render(
-    element: MixedElement,
+    element: React.MixedElement,
     containerTag: number,
     callback: ?() => void,
     concurrentRoot: ?boolean,
     options: ?RenderRootOptions,
-  ): ?ElementRef<ElementType>,
+  ): ?React.ElementRef<React.ElementType>,
   unmountComponentAtNode(containerTag: number): void,
   getNodeFromInternalInstanceHandle(
     internalInstanceHandle: InternalInstanceHandle,

filename: scripts/flow/react-native-host-hooks.js
patch: @@ -50,6 +50,10 @@ type RawEventEmitterEvent = $ReadOnly<{
   nativeEvent: {[string]: mixed, ...},
 }>;
 
+declare opaque type __PublicInstance;
+declare opaque type __PublicTextInstance;
+declare opaque type __PublicRootInstance;
+
 declare module 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface' {
   declare export function deepDiffer(
     one: any,
@@ -158,9 +162,9 @@ declare module 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'
     emit: (channel: string, event: RawEventEmitterEvent) => string,
     ...
   };
-  declare export opaque type PublicInstance;
-  declare export opaque type PublicTextInstance;
-  declare export opaque type PublicRootInstance;
+  declare export type PublicInstance = __PublicInstance;
+  declare export type PublicTextInstance = __PublicTextInstance;
+  declare export type PublicRootInstance = __PublicRootInstance;
   declare export type MeasureOnSuccessCallback = __MeasureOnSuccessCallback;
   declare export type MeasureInWindowOnSuccessCallback =
     __MeasureInWindowOnSuccessCallback;
@@ -204,6 +208,13 @@ declare module 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'
 declare module 'react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore' {
 }
 
+declare module 'react-native' {
+  declare export type HostInstance = __PublicInstance;
+  declare export type PublicTextInstance = __PublicTextInstance;
+  declare export type PublicRootInstance = __PublicRootInstance;
+  declare export type MeasureOnSuccessCallback = __MeasureOnSuccessCallback;
+}
+
 // eslint-disable-next-line no-unused-vars
 declare const RN$enableMicrotasksInReact: boolean;