迈向稳定的 JavaScript API(0.80 新变化)
在 React Native 0.80 中,我们将对 React Native 的 JavaScript API 引入两项重大变更——深度导入的废弃,以及我们新的严格 TypeScript API。这些都是我们正在进行的努力的一部分,旨在准确定义我们的 API,并为用户和框架提供可靠的类型安全。
要点速览
- 深度导入废弃:从 0.80 版本开始,我们将对从
react-native
包进行的深度导入引入废弃警告。 - 选择启用严格 TypeScript API:我们正在转向从源代码生成的 TypeScript 类型,并在 TypeScript 下建立一个新的公共 API 基准。这将实现更强、更具前瞻性的类型准确性,并且将是一次性破坏性变更。通过项目
tsconfig.json
中的compilerOptions
选项进行选择启用。 - 我们将与社区合作,逐步确保这些变更适用于所有人,然后才会在未来的 React Native 版本中默认启用严格 TypeScript API。
变更内容及原因
我们正在着手改进并稳定 React Native 的公共 JavaScript API——即您通过 'react-native'
获得的内容。
从历史上看,我们一直近似地处理这个问题。React Native 是用 Flow 编写的,但开源社区早已转向 TypeScript,公共 API 也是通过 TypeScript 消费和验证兼容性的。我们的类型曾由社区(充满爱意地)贡献,并随后合并并与我们的代码库对齐。然而,这些都依赖于手动维护且没有自动化工具,从而引入了正确性差距。
此外,我们的公共 JS API 在模块边界方面定义不佳——例如,内部 'react-native/Libraries/'
的深度导入可以被应用代码访问,但随着我们更新这些内部模块,它们可能会频繁改变。
在 0.80 版本中,我们通过废弃深度导入并引入用户选择启用新的、生成的 TypeScript API 基线来解决这些问题。我们称之为严格 TypeScript API。最终,这是未来提供稳定 React Native API 的基础。
废弃从 react-native
进行的深度导入
我们今天对 API 所做的主要改变是废弃深度导入的使用(RFC),并在 ESLint 和 JS 控制台中发出警告。值和类型的深度导入应更新为 react-native
的根导入。
// Before - import from subpath
import {Alert} from 'react-native/Libraries/Alert/Alert';
// After - import from `react-native`
import {Alert} from 'react-native';
这一改变将我们的 JavaScript API 的总表面积缩减为一组固定的导出,我们可以在未来的版本中控制并使其稳定。我们的目标是在 0.82 版本中移除这些导入路径。
某些 API 未在根目录导出,如果没有深度导入将无法使用。我们有一个开放的反馈帖,并将与社区合作最终确定公共 API 中的导出。请分享您的反馈!
选择退出
请注意,我们的目标是在未来的版本中从 React Native 的 API 中移除深度导入,因此应将其更新为根导入。
选择退出警告
ESLint
使用 overrides
禁用 no-deep-imports
规则。
overrides: [
{
files: ['*.js', '*.jsx', '*.ts', '*.tsx'],
rules: {
'@react-native/no-deep-imports': 0,
},
},
]
控制台警告
将 disableDeepImportWarnings
选项传递给 @react-native/babel-preset
。
module.exports = {
presets: [
['module:@react-native/babel-preset', {disableDeepImportWarnings: true}]
],
};
使用 --reset-cache
重启您的应用以清除 Metro 缓存。
npx @react-native-community/cli start --reset-cache
选择退出警告(Expo)
ESLint
使用 overrides
禁用 no-deep-imports
规则。
overrides: [
{
files: ['*.js', '*.jsx', '*.ts', '*.tsx'],
rules: {
'@react-native/no-deep-imports': 0,
},
},
];
控制台警告
将 disableDeepImportWarnings
选项传递给 babel-preset-expo
。
module.exports = function (api) {
api.cache(true);
return {
presets: [['babel-preset-expo', {disableDeepImportWarnings: true}]],
};
};
使用 --clear
重启您的应用以清除 Metro 缓存。
npx expo start --clear
严格 TypeScript API(选择启用)
严格 TypeScript API 是 react-native
包中一组新的 TypeScript 类型,可以通过您的 tsconfig.json
选择启用。我们正在将这些类型与现有 TS 类型一同发布,这意味着您可以选择在准备就绪时进行迁移。
新类型特性如下:
- 直接从我们的源代码生成——提高了覆盖率和正确性,因此您可以期待更强的兼容性保证。
- 限制在
react-native
的索引文件内——更严格地定义了我们的公共 API,这意味着我们在进行内部文件更改时不会破坏 API。
当社区准备好后,严格 TypeScript API 将在未来成为我们的默认 API——与深度导入的移除同步。这意味着现在开始选择启用是个好主意,因为这将使您为 React Native 未来的稳定 JS API 做好准备。
{
"extends": "@react-native/typescript-config",
"compilerOptions": {
...
"customConditions": ["react-native-strict-api"]
}
}
这将指示 TypeScript 从我们新的 types_generated/
目录解析 react-native
类型,而不是从以前的 types/
目录(手动维护)解析。无需重启 TypeScript 或您的编辑器。
破坏性变更:深度导入被禁止
如上所述,严格 TypeScript API 下的类型现在只能从主要的 'react-native'
导入路径解析,根据我们上述的废弃策略,这将强制执行包封装。
// Before - import from subpath
import {Alert} from 'react-native/Libraries/Alert/Alert';
// After - MUST import from `react-native`
import {Alert} from 'react-native';
我们已将公共 API 范围限定在 React Native 的 index.js
文件的导出中,我们对此进行精心维护。这意味着代码库中其他地方的文件更改将不再是破坏性变更。
破坏性变更:部分类型名称/形状已更改
类型现在从源代码生成,而非手动维护。这样做
- 我们统一了社区贡献类型中累积的差异——也增加了我们源代码的类型覆盖率。
- 我们有意更新了一些类型名称和类型形状,在有简化或减少歧义空间的地方进行了调整。
由于类型现在从 React Native 的源代码生成,您可以确信类型检查器对于给定版本的 react-native
始终是准确的。
示例:更严格的导出符号
Linking
API 现在是一个单一的 interface
,而不是两个导出。许多其他 API 也是如此(参见文档)。
// Before
import {Linking, LinkingStatic} from 'react-native';
function foo(linking: LinkingStatic) {}
foo(Linking);
// After
import {Linking} from 'react-native';
function foo(linking: Linking) {}
foo(Linking);
示例:修正/更完整的类型
以前的手动类型定义留下了类型缺陷的可能性。在生成的 Flow → TypeScript 下,这些缺陷不再存在(并且在源代码层面,受益于 Flow 对多平台代码的额外类型验证)。
import {Dimensions} from 'react-native';
// Before - Type error
// After - number | undefined
const {densityDpi} = Dimensions.get();
其他破坏性变更
请查阅文档中我们的专用指南,其中详细介绍了所有破坏性类型变更以及如何更新您的代码。
发布计划
我们理解 React Native 的任何破坏性变更都需要开发者花费时间在其应用中进行更新。
现在 — 选择启用发布 (0.80)
"react-native-strict-api"
选择启用在 0.80 版本中是稳定的。
- 这是一次性迁移。我们旨在让应用和库在接下来的几个版本中按自己的节奏选择启用。
- 在任一模式下,您的应用在运行时都不会有任何变化——这只影响 TypeScript 分析。
- 此外,我们将通过我们的专用反馈帖收集有关缺失 API 的反馈。
严格 TypeScript API 将在未来成为我们的默认 API。
如果您有时间,现在就值得在您的 tsconfig.json
中测试选择启用,以使您的应用或库面向未来。这将立即评估在严格 API 下您的应用是否引入了任何类型错误。可能根本没有(!)——在这种情况下,您就可以继续了。
未来 — 默认启用严格 TypeScript API
将来,我们将要求所有代码库使用我们的严格 API,并移除旧有的类型。
此时间表将基于社区反馈。在至少接下来的两个 React Native 版本中,严格 API 将保持为选择启用。
常见问题
我目前正在使用子路径导入。我该怎么做?
请迁移到根 'react-native'
导入路径。
- 子路径导入(例如
'react-native/Libraries/Alert/Alert'
)正在成为私有 API。如果不阻止访问 React Native 内部的实现文件,我们将无法提供稳定的 JavaScript API。 - 我们希望废弃警告能促使社区反馈,如果您认为我们没有暴露对您的应用至关重要的代码路径,可以通过我们的集中讨论帖提出。在合理的情况下,我们可能会将 API 提升到索引导出。
我是一个库维护者。这项变更对我有什么影响?
应用和库都可以按照自己的节奏选择启用,因为 tsconfig.json
只会影响当前的代码库。
- 通常,在 React Native 项目中,
node_modules
会被 TypeScript 服务器排除在验证之外。因此,您的包的导出类型定义是真相的来源。
💡 我们需要反馈!与子路径导入变更一样,如果您在使用严格 API 时遇到任何集成问题,请在 GitHub 上告知我们。
这是否保证了 React Native 的最终 API?
很遗憾,目前还不能。在 0.80 版本中,我们投入了工具开发,以便 React Native 现有的 JS API 基线可以通过 TypeScript 准确消费——从而实现未来的稳定更改。我们正在规范化您所熟悉和喜爱的现有 API。
将来,我们将采取行动最终确定我们在核心中提供的 API——跨越每种语言表面。API 变更将通过 RFC/公告进行沟通,并且通常会有一个废弃周期。
为什么 React Native 不是用 TypeScript 编写的?
React Native 是 Meta 的核心基础设施。在将每个合并的更改公开发布到开源之前,我们会在我们的应用家族中进行测试。
在如此规模和敏感度下,正确性至关重要。底线是 Flow 为我们提供了比 TypeScript 更高的性能和更强的严格性,包括对 React Native 的特定多平台支持。
致谢
这些更改得益于 Iwo Plaza、Jakub Piasecki、Dawid Małecki、Alex Hunt 和 Riccardo Cipolleschi 的贡献。
同时感谢 Pieter Vanderwerff、Rubén Norte 和 Rob Hogan 提供的额外帮助和建议。
观看演讲! 在 App.js 2025 上,我们深入探讨了严格 TypeScript API 背后的动机和工作。 在 YouTube 上观看
