Skip to content

Enable Strict TS API by default (#57490) - #57490

Closed
huntie wants to merge 3 commits into
react:mainfrom
huntie:export-D110458670
Closed

Enable Strict TS API by default (#57490)#57490
huntie wants to merge 3 commits into
react:mainfrom
huntie:export-D110458670

Conversation

@huntie

@huntiehuntie commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary:

See RFC0894: Removing deep imports from react-native

This is the big switch to enable the Strict TypeScript API (generated types + single index entry point) by default in React Native.

Opt-in → opt-out

After this change, the main react-native package resolves its "types" entry points only to types_generated/index.d.ts — with no other subpaths available.

The new "react-native-legacy-deep-imports" condition maps to legacy types/ and Libraries/*.d.ts sources.

Impact limitation: For this stage of rollout, the "default" condition continues to resolve to source files. Only TypeScript is affected.

How to opt out

Opposite of today's opt-in, which we will update in the docs. Again, the only impact area today is TypeScript.

// tsconfig.json{"extends": "@react-native/typescript-config","compilerOptions": {
...
"customConditions": ["react-native-legacy-deep-imports"]}}

Other changes

  • Drop @react-native/typescript-config/strict entry point, update README.
  • Update __typetests__.

Rollout plan

Target release: 0.87. This and the contributing stack will be cherry picked for RC1.

  • We've conducted testing against 100+ real Expo codebases, giving us the confidence that we've reduced breaking changes enough that the vast majority of RN codebases can migrate.
  • The Strict API includes a number of intentional breaking changes, and docs have been kept up to date.
  • We're shipping a /migrate-to-strict-api skill to migrate via agents, see Add migrate-to-strict-api skill react-native-community/skills#3.

What's improved since 0.80?

Since the initial opt-in launch of the Strict API in 0.80, we've been making continuous improvements over the last year to get our generated types into a widely launchable state.

Most notably:

Rollback plan

Revert this diff.

IMPORTANT: We'll adopt a policy of super-eager rollback, if there are any unsolvable issues during the RC phase.

Changelog:
[General][Breaking] - React Native's default JavaScript API is now the Strict TypeScript API. Use customConditions: ["react-native-legacy-deep-imports"] to opt out.

Reviewed By: cortinico

Differential Revision: D110458670

@meta-clameta-claBot 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 Jul 8, 2026
@meta-codesync

Copy link
Copy Markdown

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

@meta-codesyncmeta-codesyncBot changed the title Enable Strict TS API by defaultEnable Strict TS API by default (#57490)Jul 9, 2026
@huntie
huntieforce-pushed the export-D110458670 branch from 1105931 to 246fc19CompareJuly 9, 2026 16:43
huntie added a commit to huntie/react-native that referenced this pull request Jul 9, 2026
Summary:
See [**RFC0894: Removing deep imports from react-native**](react-native-community/discussions-and-proposals#894)
TODO: Description to come.
Differential Revision: D110458670
huntie added a commit to huntie/react-native that referenced this pull request Jul 9, 2026
Summary:
See [**RFC0894: Removing deep imports from react-native**](react-native-community/discussions-and-proposals#894)
TODO: Description to come.
Differential Revision: D110458670
@huntie
huntieforce-pushed the export-D110458670 branch from 246fc19 to 1d07743CompareJuly 9, 2026 18:29
huntie added a commit to huntie/react-native that referenced this pull request Jul 9, 2026
Summary:
See [**RFC0894: Removing deep imports from react-native**](react-native-community/discussions-and-proposals#894)
TODO: Description to come.
Differential Revision: D110458670
@huntie
huntieforce-pushed the export-D110458670 branch from 1d07743 to da00fc8CompareJuly 9, 2026 18:36
huntie added a commit to huntie/react-native that referenced this pull request Jul 9, 2026
Summary:
See [**RFC0894: Removing deep imports from react-native**](react-native-community/discussions-and-proposals#894)
TODO: Finish tidying up description below.
Differential Revision: D110458670
@huntie
huntieforce-pushed the export-D110458670 branch from da00fc8 to cc19a4aCompareJuly 9, 2026 18:37

@cortinicocortinico left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review automatically exported from Phabricator review in Meta.

huntie added 3 commits July 10, 2026 05:56
Summary:
See [**RFC0894: Removing deep imports from react-native**](react-native-community/discussions-and-proposals#894)
Exposes a `'react-native/react-private-interface'` subpath export on the main package, to replace `Libraries/ReactPrivate/ReactNativePrivateInterface.js`.
**Impact: Internal**
This is a private contract between `react` and `react-native`.
- `ReactNativePrivateInterface` is deprecated and we'll migrate React call sites in a future version before cleanup.
**Naming**
Translate directly to `react-private-interface` ("private interface for React"). There's alternatives here but the explicitness and continuity is helpful, I believe.
Changelog: [Internal]
Reviewed By: robhogan
Differential Revision: D111231527
Summary:
See [**RFC0894: Removing deep imports from react-native**](react-native-community/discussions-and-proposals#894)
Adds a `'react-native/unstable-internals-do-not-use'` entry point that acts as an explicit, opt-in escape hatch for frameworks and libraries that depend on specific React Native internals.
Follows (and supersedes) react-native-community/discussions-and-proposals#985.
Resolves T270727304.
**Motivation**
- Maintains a known list of which React Native internals are still in use.
- Decouples removal of the Strict API opt-out from the longer-term decisions about these APIs.
- Lets us relocate supporting source files freely, since consumers reference this subpath instead of deep internal paths.
**Notes**
- Reuses the runtime **object-with-getter pattern** (same as `index.js`), to avoid any native module side effects caused by loading adjacent file exports.
- e.g. in Expo, [`hmrUtils.js`](https://github.com/expo/expo/blob/2d07e3a17f4be2284bbf579d8825fe32f762ce1a/packages/expo/src/async-require/hmrUtils.native.ts?fbclid=IwY2xjawS7GjNwZG9mA2V4dG4DYWVtAjExAGJyaWQRMTZ1ckEwU05oWUw2bDBVN21zcnRjBmFwcF9pZAEwAAEen3UuX4Ig-RD3n1ULZIHIHq21Mfk_ci9b2SxquY7UkngDs6qhnRt5YQlb8Os_aem_ylJy40egSOl1qhZ9bA9HTA) is designed to be run early in RN startup — preserve the lazy require characteristic and do not break this.
- TypeScript defs on this API are minimal, with complex internal input/handle types reduced to `unknown`. As with D110602194, these are intended to be feature-locked.
**Exposed internals and known consumers**
NOTE: The exports the community needs have reduced slightly since the spreadsheet in RFC0895 and would almost all align with `devsupport`. However, we're explicitly leaving a decision to formalise until later, and we may need to add in extra APIs quickly based on RC feedback.
| Export | Source module | Known consumers |
|---|---|---|
| `AppContainer` | `Libraries/ReactNative/AppContainer` | react-native-screens ([DebugContainer.tsx](https://github.com/software-mansion/react-native-screens/blob/6f38d76129d40cc8145d06b98f885b508fa7bf2d/src/components/DebugContainer.tsx#L5)) |
| `AssetSourceResolver` | `Libraries/Image/AssetSourceResolver` | Re.pack ([IncludeModules.ts](https://github.com/callstack/repack/blob/2498b3a426203daa4b81c7e6f7a88e86d88e77b9/packages/repack/src/modules/IncludeModules.ts#L9)) |
| `customDirectEventTypes` | `Libraries/Renderer/shims/ReactNativeViewConfigRegistry` | react-native-gesture-handler ([customDirectEventTypes.ts](https://github.com/software-mansion/react-native-gesture-handler/blob/ee147abf364bef48a02d3cf437572b4dddd30bec/packages/react-native-gesture-handler/src/handlers/customDirectEventTypes.ts#L2)) |
| `DevLoadingView` | `Libraries/Utilities/DevLoadingView` | Expo ([hmrUtils.native.ts](https://github.com/expo/expo/blob/2d07e3a17f4be2284bbf579d8825fe32f762ce1a/packages/expo/src/async-require/hmrUtils.native.ts)), Re.pack ([WebpackHMRClient.ts](https://github.com/callstack/repack/blob/2498b3a426203daa4b81c7e6f7a88e86d88e77b9/packages/repack/src/modules/WebpackHMRClient.ts)) |
| `getDevServer` | `Libraries/Core/Devtools/getDevServer` | Expo ([getDevServer.native.ts](https://github.com/expo/expo/blob/2d07e3a17f4be2284bbf579d8825fe32f762ce1a/packages/expo/src/async-require/getDevServer.native.ts), [hmrUtils.native.ts](https://github.com/expo/expo/blob/2d07e3a17f4be2284bbf579d8825fe32f762ce1a/packages/expo/src/async-require/hmrUtils.native.ts), [base.ts](https://github.com/expo/expo/blob/2d07e3a17f4be2284bbf579d8825fe32f762ce1a/packages/expo/src/dom/base.ts), [getDevServer.native.ts](https://github.com/expo/expo/blob/2d07e3a17f4be2284bbf579d8825fe32f762ce1a/packages/expo/metro-runtime/src/getDevServer.native.ts), [devServerEndpoints.ts](https://github.com/expo/expo/blob/2d07e3a17f4be2284bbf579d8825fe32f762ce1a/packages/expo/log-box/src/utils/devServerEndpoints.ts), [getConnectionInfo.native.ts](https://github.com/expo/expo/blob/2d07e3a17f4be2284bbf579d8825fe32f762ce1a/packages/expo/devtools/src/getConnectionInfo.native.ts), [index.native.ts](https://github.com/expo/expo/blob/2d07e3a17f4be2284bbf579d8825fe32f762ce1a/packages/expo-router/src/getDevServer/index.native.ts)) |
| `HMRClient` | `Libraries/Utilities/HMRClient` | Expo ([metroServerLogs.native.ts](https://github.com/expo/expo/blob/2d07e3a17f4be2284bbf579d8825fe32f762ce1a/packages/expo/metro-runtime/src/metroServerLogs.native.ts)) |
| `NativeExceptionsManager` | `Libraries/Core/NativeExceptionsManager` | Expo ([hmrUtils.native.ts](https://github.com/expo/expo/blob/2d07e3a17f4be2284bbf579d8825fe32f762ce1a/packages/expo/src/async-require/hmrUtils.native.ts)), Re.pack ([WebpackHMRClient.ts](https://github.com/callstack/repack/blob/2498b3a426203daa4b81c7e6f7a88e86d88e77b9/packages/repack/src/modules/WebpackHMRClient.ts)) |
| `NativeRedBox` | `Libraries/NativeModules/specs/NativeRedBox` | Expo ([hmrUtils.native.ts](https://github.com/expo/expo/blob/2d07e3a17f4be2284bbf579d8825fe32f762ce1a/packages/expo/src/async-require/hmrUtils.native.ts)), Re.pack ([WebpackHMRClient.ts](https://github.com/callstack/repack/blob/2498b3a426203daa4b81c7e6f7a88e86d88e77b9/packages/repack/src/modules/WebpackHMRClient.ts)) |
| `NativeSourceCode` | `Libraries/NativeModules/specs/NativeSourceCode` | Expo ([getBundleUrl.native.ts](https://github.com/expo/expo/blob/2d07e3a17f4be2284bbf579d8825fe32f762ce1a/packages/expo/src/utils/getBundleUrl.native.ts)) |
| `PressabilityDebugView` | `Libraries/Pressability/PressabilityDebug` | react-native-gesture-handler ([PressabilityDebugView.tsx](https://github.com/software-mansion/react-native-gesture-handler/blob/ee147abf364bef48a02d3cf437572b4dddd30bec/packages/react-native-gesture-handler/src/handlers/PressabilityDebugView.tsx#L2)) |
**Alternative names**
- `unstable-frameworks`
- `unstable-devsupport`
- `frameworks-private-interface` (mirroring `ReactPrivateInterface.js`) — this is likely a future stable shape candidate.
Changelog: [Internal]
Reviewed By: rubennorte
Differential Revision: D110911864
Summary:
See [**RFC0894: Removing deep imports from react-native**](react-native-community/discussions-and-proposals#894)
TODO: Finish tidying up description below.
Reviewed By: cortinico
Differential Revision: D110458670
@huntie
huntieforce-pushed the export-D110458670 branch from cc19a4a to 0441eecCompareJuly 10, 2026 12:57
@meta-codesyncmeta-codesyncBot added the Merged This PR has been merged. label Jul 10, 2026
@meta-codesync

Copy link
Copy Markdown

This pull request has been merged in c948b61.

huntie added a commit to huntie/react-native that referenced this pull request Jul 10, 2026
Summary:
Pull Request resolved: react#57490
See [**RFC0894: Removing deep imports from react-native**](react-native-community/discussions-and-proposals#894)
This is the **big switch** to enable the Strict TypeScript API (generated types + single index entry point) by default in React Native.
**Opt-in → opt-out**
After this change, the main `react-native` package resolves its `"types"` entry points only to `types_generated/index.d.ts` — with no other subpaths available.
The new `"react-native-legacy-deep-imports"` condition maps to legacy `types/` and `Libraries/*.d.ts` sources.
**Impact limitation**: For this stage of rollout, the `"default"` condition continues to resolve to source files. Only TypeScript is affected.
**How to opt out**
Opposite of today's opt-in, which we will update in [the docs](https://reactnative.dev/docs/strict-typescript-api). Again, the only impact area today is **TypeScript**.
```json5
// tsconfig.json
{
"extends": "react-native/typescript-config",
"compilerOptions": {
...
"customConditions": ["react-native-legacy-deep-imports"]
}
}
```
**Other changes**
- Drop `react-native/typescript-config/strict` entry point, update README.
- Update `__typetests__`.
**Rollout plan**
**Target release: 0.87**. This and the contributing stack will be cherry picked for RC1.
- We've conducted testing against 100+ real Expo codebases, giving us the confidence that we've reduced breaking changes enough that the vast majority of RN codebases can migrate.
- The Strict API includes a number of **intentional breaking changes**, and docs have been kept up to date.
- We're shipping a `/migrate-to-strict-api` skill to migrate via agents, see react-native-community/skills#3.
**What's improved since 0.80?**
Since the initial opt-in launch of the Strict API in 0.80, we've been making continuous improvements over the last year to get our generated types into a widely launchable state.
Most notably:
- 21+ new/updated root APIs and fixes due to community feedback ([discussion](react-native-community/discussions-and-proposals#893), [PRs](https://github.com/react/react-native/pulls?q=is%3Apr%20label%3A%22JS%20API%20stabilization%20(1.0)%22%20is%3Aclosed)).
- Upstream encapsulation blocker in TypeScript, fixed in 6.0 (react#53565).
- Tailwind/Uniwind compatibility (`interface` types for props).
- `*Instance` ref type exports for all built-in components (react-native-community/discussions-and-proposals#1003).
- Fixes to previously mistyped, high impact APIs, such as `Appearance`.
- New subpath entry points for `asset-registry`, `setup-env`, and others.
- Refinements to doc comments/type translation build.
**Rollback plan**
Revert this diff.
IMPORTANT: We'll adopt a policy of **super-eager rollback**, if there are any unsolvable issues during the RC phase.
Changelog:
[General][Breaking] - React Native's default JavaScript API is now the [Strict TypeScript API](https://reactnative.dev/docs/strict-typescript-api). Use `customConditions: ["react-native-legacy-deep-imports"]` to opt out.
Reviewed By: cortinico
Differential Revision: D110458670
fbshipit-source-id: 4b0e0b458a5f895f783d6d936e7b11ccff2df076
@huntie
huntie deleted the export-D110458670 branch July 10, 2026 16:46
zeyap pushed a commit that referenced this pull request Jul 13, 2026
Summary:
Pull Request resolved: #57490
See [**RFC0894: Removing deep imports from react-native**](react-native-community/discussions-and-proposals#894)
This is the **big switch** to enable the Strict TypeScript API (generated types + single index entry point) by default in React Native.
**Opt-in → opt-out**
After this change, the main `react-native` package resolves its `"types"` entry points only to `types_generated/index.d.ts` — with no other subpaths available.
The new `"react-native-legacy-deep-imports"` condition maps to legacy `types/` and `Libraries/*.d.ts` sources.
**Impact limitation**: For this stage of rollout, the `"default"` condition continues to resolve to source files. Only TypeScript is affected.
**How to opt out**
Opposite of today's opt-in, which we will update in [the docs](https://reactnative.dev/docs/strict-typescript-api). Again, the only impact area today is **TypeScript**.
```json5
// tsconfig.json
{
"extends": "react-native/typescript-config",
"compilerOptions": {
...
"customConditions": ["react-native-legacy-deep-imports"]
}
}
```
**Other changes**
- Drop `react-native/typescript-config/strict` entry point, update README.
- Update `__typetests__`.
**Rollout plan**
**Target release: 0.87**. This and the contributing stack will be cherry picked for RC1.
- We've conducted testing against 100+ real Expo codebases, giving us the confidence that we've reduced breaking changes enough that the vast majority of RN codebases can migrate.
- The Strict API includes a number of **intentional breaking changes**, and docs have been kept up to date.
- We're shipping a `/migrate-to-strict-api` skill to migrate via agents, see react-native-community/skills#3.
**What's improved since 0.80?**
Since the initial opt-in launch of the Strict API in 0.80, we've been making continuous improvements over the last year to get our generated types into a widely launchable state.
Most notably:
- 21+ new/updated root APIs and fixes due to community feedback ([discussion](react-native-community/discussions-and-proposals#893), [PRs](https://github.com/react/react-native/pulls?q=is%3Apr%20label%3A%22JS%20API%20stabilization%20(1.0)%22%20is%3Aclosed)).
- Upstream encapsulation blocker in TypeScript, fixed in 6.0 (#53565).
- Tailwind/Uniwind compatibility (`interface` types for props).
- `*Instance` ref type exports for all built-in components (react-native-community/discussions-and-proposals#1003).
- Fixes to previously mistyped, high impact APIs, such as `Appearance`.
- New subpath entry points for `asset-registry`, `setup-env`, and others.
- Refinements to doc comments/type translation build.
**Rollback plan**
Revert this diff.
IMPORTANT: We'll adopt a policy of **super-eager rollback**, if there are any unsolvable issues during the RC phase.
Changelog:
[General][Breaking] - React Native's default JavaScript API is now the [Strict TypeScript API](https://reactnative.dev/docs/strict-typescript-api). Use `customConditions: ["react-native-legacy-deep-imports"]` to opt out.
Reviewed By: cortinico
Differential Revision: D110458670
fbshipit-source-id: 4b0e0b458a5f895f783d6d936e7b11ccff2df076
m-bert added a commit to software-mansion/react-native-gesture-handler that referenced this pull request Jul 20, 2026
## Description
Since React Native 0.87, Strict TS API is [enabled by default
](react/react-native#57490). This PR brings
necessary changes to resolve ts-errors on 0.87.
This PR also removes `cursor: undefined;` from `iOS`, but now it is a
valid prop - this workaround was necessary on old arch
## Test plan
`yarn ts-check`
leotm added a commit to leotm/react-native-template-new-architecture that referenced this pull request Jul 20, 2026
- 0.88.0-nightly-20260720-e64027865
- react/react-native@e04ff69...e640278
- Bump RN deps and devDeps (@react-native: babel/jest preset, eslint/metro/ts configs)
- Bump Jest snapshot test rendered RN ver
- Update lockfiles (Yarn, CocoaPods)
- Update iOS privacy manifest
- Bump ReadMe ver
- Opt out of RN default Strict TS API for RNsafeareacontext
- react/react-native#57490
- #2041
- @lavamoat/react-native-lockdown unaffected by
- react/react-native#57482 deprecated rn-get-polyfills unused
- react/react-native#57475
- only hooking into Metro serializer opts getPolyfills and getRunModuleStatement
- react-native/packages/community-cli-plugin: getModulesRunBeforeMainModule updated from /Libraries/Core/InitializeCore to /setup-env in core
Resolve: #2031
leotm added a commit to leotm/react-native-template-new-architecture that referenced this pull request Aug 12, 2026
- react/react-native#57490 example overwrites react-native by mistake
- preserve react-native config like github.com/react/react-native/tree/main/packages/typescript-config
@jakebailey

Copy link
Copy Markdown

This broke a lot of DefinitelyTyped packages: DefinitelyTyped/DefinitelyTyped#75402

In particular, changing from interfaces to type aliases means that the types can no longer be extended, which breaks react-native-web, which extends certain types with web specific extras.

I don't think that interfaces are really any less strict than type aliases, and are a breaking change for any types out there using the fact that they're interfaces.

Would you consider undoing some of this?

@huntie

Copy link
Copy Markdown
ContributorAuthor

@jakebailey Which version did you test and which types collided? This is something we directly addressed in 0.87 — and if there's extra gaps, we can adjust.

@jakebailey

Copy link
Copy Markdown

DT is unpinned, so it's the latest.

If you look at https://github.com/DefinitelyTyped/DefinitelyTyped/actions/runs/32138113480, all failures (except maybe one or two) are due to react-native. The PR linked above shows the full set, but mainly it's react-native-web that has the problem.

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

Labels

CLA SignedThis label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.MergedThis PR has been merged.meta-exportedp: FacebookPartner: FacebookPartner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@huntie@jakebailey@cortinico