迈向稳定的 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 也正是通过它来消费和验证兼容性的。我们的类型一直由社区(充满爱地)贡献,并随后在我们的代码库中合并和对齐。然而,这些都依赖于手动维护,没有自动化工具,从而引入了正确性差距。
此外,我们的公共 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/ 目录而不是之前的 types/ 目录(手动维护)解析 react-native 类型。无需重启 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 版本中,我们投入了工具,以便通过 TypeScript 准确地使用 React Native 现有的 JS API 基线——从而实现未来的稳定更改。我们正在规范化您所熟悉和喜爱的现有 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 的额外帮助和建议。




