跳到主要内容

迈向稳定的 JavaScript API(0.80 新变化)

·10 分钟阅读
Alex Hunt
Alex Hunt
Meta 软件工程师
Iwo Plaza
Iwo Plaza
Software Mansion 软件工程师
Jakub Piasecki
Jakub Piasecki
Software Mansion 软件工程师
Dawid Małecki
Dawid Małecki
Software Mansion 软件工程师

在 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 未在根目录导出,如果没有深度导入将无法使用。我们有一个开放的反馈帖,并将与社区合作最终确定公共 API 中的导出。请分享您的反馈!

选择退出

请注意,我们的目标是在未来的版本中从 React Native 的 API 中移除深度导入,因此应将其更新为根导入。

选择退出警告

ESLint

使用 overrides 禁用 no-deep-imports 规则。

.eslintrc.js
  overrides: [
{
files: ['*.js', '*.jsx', '*.ts', '*.tsx'],
rules: {
'@react-native/no-deep-imports': 0,
},
},
]

控制台警告

disableDeepImportWarnings 选项传递给 @react-native/babel-preset

babel.config.js
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 规则。

.eslintrc.js
overrides: [
{
files: ['*.js', '*.jsx', '*.ts', '*.tsx'],
rules: {
'@react-native/no-deep-imports': 0,
},
},
];

控制台警告

disableDeepImportWarnings 选项传递给 babel-preset-expo

babel.config.js
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 类型一同发布,这意味着您可以选择在准备就绪时进行迁移。

新类型特性如下:

  1. 直接从我们的源代码生成——提高了覆盖率和正确性,因此您可以期待更强的兼容性保证。
  2. 限制在 react-native 的索引文件内——更严格地定义了我们的公共 API,这意味着我们在进行内部文件更改时不会破坏 API。

当社区准备好后,严格 TypeScript API 将在未来成为我们的默认 API——与深度导入的移除同步。这意味着现在开始选择启用是个好主意,因为这将使您为 React Native 未来的稳定 JS API 做好准备。

tsconfig.json
{
"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 PlazaJakub PiaseckiDawid MałeckiAlex HuntRiccardo Cipolleschi 的贡献。

同时感谢 Pieter VanderwerffRubén NorteRob Hogan 提供的额外帮助和建议。

了解更多

观看演讲! 在 App.js 2025 上,我们深入探讨了严格 TypeScript API 背后的动机和工作。 在 YouTube 上观看

App.js 2025 Talk