安定したJavaScript APIに向けて (0.80での新しい変更点)
React Native 0.80では、React NativeのJavaScript APIに2つの重要な変更を導入します。それは、ディープインポートの非推奨化と、新しいStrict TypeScript APIです。これらは、APIを正確に定義し、ユーザーやフレームワークに信頼性の高い型安全性を提供するための継続的な取り組みの一環です。
主なポイント
- ディープインポートの非推奨化: 0.80から、
react-native
パッケージからのディープインポートに対して非推奨の警告を導入します。 - オプトインのStrict TypeScript API: 私たちは、ソースコードから生成されるTypeScriptの型と、TypeScriptに基づく新しい公開APIのベースラインに移行しています。これにより、より強力で将来性のある型の正確性が可能になり、これは一度限りの破壊的変更となります。プロジェクトの
tsconfig.json
にあるcompilerOptions
経由でオプトインしてください。 - 将来のReact NativeリリースでStrict TypeScript APIをデフォルトで有効にする前に、これらの変更が誰にとっても機能するように、時間をかけてコミュニティと協力していきます。
何が変わり、なぜ変わるのか
私たちは、React Nativeの公開JavaScript API、つまり'react-native'
をインポートしたときに得られるものを改善し、安定させる方向へ進んでいます。
歴史的に、私たちはこれを近似的に扱ってきました。React NativeはFlowで書かれていますが、コミュニティはオープンソースにおいてTypeScriptへと移行して久しく、公開APIもTypeScriptによって利用され、互換性が検証されています。私たちの型定義は(愛情を込めて)コミュニティによって提供され、その後私たちのコードベースにマージ・調整されてきました。しかし、これらは手動でのメンテナンスに依存しており、自動化されたツールがなかったため、正確性にギャップが生じていました。
加えて、私たちの公開JS APIはモジュールの境界という点で定義が曖昧でした。例えば、内部的な'react-native/Libraries/'
へのディープインポートはアプリのコードからアクセス可能でしたが、私たちがこれらの内部実装を更新するたびに頻繁に変更される可能性がありました。
0.80では、ディープインポートを非推奨にし、ユーザーがオプトインできる新しい生成されたTypeScriptのAPIベースラインを導入することで、これらの問題に対処します。これを私たちはStrict 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,
},
},
]
コンソール警告
@react-native/babel-preset
にdisableDeepImportWarnings
オプションを渡します。
module.exports = {
presets: [
['module:@react-native/babel-preset', {disableDeepImportWarnings: true}]
],
};
Metroのキャッシュをクリアするために、--reset-cache
を付けてアプリを再起動してください。
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,
},
},
];
コンソール警告
babel-preset-expo
にdisableDeepImportWarnings
オプションを渡します。
module.exports = function (api) {
api.cache(true);
return {
presets: [['babel-preset-expo', {disableDeepImportWarnings: true}]],
};
};
Metroのキャッシュをクリアするために、--clear
を付けてアプリを再起動してください。
npx expo start --clear
Strict TypeScript API (オプトイン)
Strict TypeScript APIは、react-native
パッケージ内の新しいTypeScriptの型セットで、tsconfig.json
を通じてオプトインできます。これらは既存のTS型と並行して提供されるため、準備ができたタイミングで移行を選択できます。
新しい型は以下の特徴があります
- 私たちのソースコードから直接生成される — カバレッジと正確性が向上し、より強力な互換性保証を期待できます。
react-native
のindexファイルに制限される — 公開APIをより厳密に定義し、内部ファイルの変更がAPIの破壊的変更にならないことを意味します。
コミュニティの準備が整い次第、Strict TypeScript APIは将来的に私たちのデフォルトAPIとなり、ディープインポートの削除と同期します。これは、将来の安定したReact Native JS APIに備えるために、オプトインを開始することが良い考えであることを意味します。
{
"extends": "@react-native/typescript-config",
"compilerOptions": {
...
"customConditions": ["react-native-strict-api"]
}
}
これにより、TypeScriptはreact-native
の型を、以前のtypes/
ディレクトリ(手動でメンテナンスされていた)の代わりに、新しいtypes_generated/
ディレクトリから解決するようになります。TypeScriptやエディタの再起動は不要です。
破壊的変更: ディープインポートが禁止されます
上述の通り、Strict 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は、2つのエクスポートではなく、単一の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については、専用のフィードバックスレッドを通じてフィードバックを受け付けます。
Strict TypeScript APIは将来的に私たちのデフォルトAPIになります。
もし時間があれば、あなたのアプリやライブラリを将来に対応させるために、今すぐtsconfig.json
でオプトインを試す価値があります。これにより、Strict API下であなたのアプリに型の問題が導入されたかどうかをすぐに評価できます。何もないかもしれません(!) — その場合は、準備万端です。
将来 — Strict TypeScript APIがデフォルトに
将来的に、すべてのコードベースでStrict APIの使用を必須とし、レガシーな型を削除する予定です。
このタイムラインはコミュニティのフィードバックに基づいて決定されます。少なくとも次の2つのReact Nativeリリースでは、Strict APIはオプトインのままとなります。
FAQ
現在サブパスインポートを使用しています。どうすればよいですか?
ルートの'react-native'
インポートパスへの移行をお願いします。
- サブパスインポート(例:
'react-native/Libraries/Alert/Alert'
)はプライベートAPIになります。React Native内部の実装ファイルへのアクセスを防がなければ、安定したJavaScript APIを提供することはできません。 - 私たちは、非推奨の警告がコミュニティからのフィードバックを促すことを望んでいます。もしあなたのアプリにとって重要なコードパスが公開されていないと思われる場合は、一元化されたディスカッションスレッドで問題を提起してください。正当な理由があれば、APIをindexエクスポートに昇格させる可能性があります。
私はライブラリのメンテナーです。この変更は私にどのような影響を与えますか?
tsconfig.json
は直接のコードベースにのみ影響するため、アプリもライブラリもそれぞれのペースでオプトインできます。
- 通常、React Nativeプロジェクトでは
node_modules
はTypeScriptサーバーによる検証から除外されます。したがって、あなたのパッケージのエクスポートされた型定義が信頼できる情報源となります。
💡 フィードバックを求めています! 変更されたサブパスインポートと同様に、Strict APIとの統合で問題が発生した場合は、GitHubでお知らせください。
これはReact Nativeの最終的なAPIを保証するものですか?
残念ながら、まだです。0.80では、React Nativeの既存のJS APIベースラインがTypeScriptを通じて正確に利用できるようにするためのツールへの投資を行いました。これにより、将来の安定した変更が可能になります。私たちは、皆さんが既に知っていて愛用している既存のAPIを形式化している段階です。
将来的に、私たちはコアで現在提供しているAPIを、各言語のインターフェースにわたって最終決定するためのアクションを起こします。APIの変更はRFCやアナウンスを通じて伝えられ、通常は非推奨サイクルを伴います。
なぜReact NativeはTypeScriptで書かれていないのですか?
React NativeはMetaにおけるコアインフラです。私たちは、マージされたすべての変更を、一般のオープンソースで利用可能になる前に、私たちのFamily of Apps全体でテストしています。
この規模と機密性においては、正確さが重要です。結論として、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にて、私たちの動機とStrict TypeScript APIの背後にある作業について詳しく解説しました。 YouTubeで見る
