目次

Null safetyへの移行

このページでは、コードをNull safetyに移行する方法と時期について説明します。これは、所有する各パッケージを移行するための基本的な手順です。

  1. 待つ 依存しているパッケージが移行されるのを待ちます。
  2. 移行する パッケージのコードを、できれば対話型の移行ツールを使用して移行します。
  3. 静的解析する パッケージのコードを静的に解析します。
  4. テストする 変更が機能することを確認するためにテストします。
  5. パッケージが既にpub.devにある場合は、公開する Null safety対応バージョンをプレリリースバージョンとして公開します。

移行ツールの使用感をざっくりと確認するには、次のビデオをご覧ください。


DartパッケージをNull safetyに移行する方法

1. 移行を待つ

#

依存関係グラフの葉から順に移行することを強くお勧めします。たとえば、パッケージCがパッケージBに依存し、パッケージBがパッケージAに依存する場合、最初にAをNull safetyに移行し、次にB、最後にCに移行します。

Illustration of C/B/A sentence

依存関係がNull safetyをサポートする前に移行できますが、依存関係の移行時にコードを変更する必要がある場合があります。たとえば、関数がnull許容パラメータを受け取ると予測しますが、パッケージがそれをnull非許容に変更した場合、null許容引数を渡すとコンパイルエラーになります。

このセクションでは、Null safetyモードでdart pub outdatedコマンドを使用して、パッケージの依存関係を確認および更新する方法について説明します。これらの手順では、変更を簡単に元に戻せるように、コードがソース管理下にあることを前提としています。

Dart 2.19.6リリースに切り替える

#

Dart SDKの2.19.6リリースに切り替えます。これはFlutter 3.7.12 SDKに含まれています。

Dart 2.19.6があることを確認する

$ dart --version
Dart SDK version: 2.19.6

依存関係の状態を確認する

#

次のコマンドを使用して、パッケージの依存関係の移行状態を確認します。

$ dart pub outdated --mode=null-safety

出力で、すべてのパッケージがNull safetyをサポートしていると表示された場合は、移行を開始できます。それ以外の場合は、Resolvable列を使用して、Null safety対応のリリースが存在するかどうかを確認します。

単純なパッケージの出力例を以下に示します。各パッケージの緑色のチェックマーク付きバージョンはNull safetyをサポートしています。

Output of dart pub outdated

出力は、パッケージのすべての依存関係にNull safetyをサポートする解決可能なプレリリースがあることを示しています。

パッケージの依存関係のいずれかがまだNull safetyをサポートしていない場合は、パッケージの所有者にお問い合わせください。pub.devのパッケージページで連絡先情報を見つけることができます。

依存関係を更新する

#

パッケージのコードを移行する前に、その依存関係をNull safety対応バージョンに更新します。

  1. dart pub upgrade --null-safetyを実行して、Null safetyをサポートする最新バージョンにアップグレードします。注記:このコマンドはpubspec.yamlファイルを変更します。

  2. dart pub getを実行します。

2. 移行する

#

コードをNull safety対応にするために必要な変更のほとんどは、簡単に予測できます。たとえば、変数がnullになる可能性がある場合、その型には?サフィックスが必要です。名前付きパラメータがnull許容であってはならない場合は、requiredを指定するか、デフォルト値を指定します。

移行には2つの方法があります。

移行ツールを使用する

#

移行ツールは、Null safety非対応のDartコードのパッケージを受け取り、Null safety対応に変換します。 ヒントマーカーをDartコードに追加することで、ツールの変換をガイドできます。

ツールを開始する前に、準備が整っていることを確認してください。

  • Dart SDKの2.19.6リリースを使用します。
  • dart pub outdated --mode=null-safetyを使用して、すべての依存関係がNull safety対応で最新であることを確認します。

パッケージのpubspec.yamlファイルを含むディレクトリで、dart migrateコマンドを実行して移行ツールを開始します。

$ dart migrate

パッケージが移行の準備ができている場合、ツールは次のような行を出力します。

View the migration suggestions by visiting:

  http://127.0.0.1:60278/Users/you/project/mypkg.console-simple?authToken=Xfz0jvpyeMI%3D

ChromeブラウザでそのURLにアクセスして、移行プロセスをガイドできる対話型UIを表示します。

Screenshot of migration tool

変数と型アノテーションごとに、ツールが推論するnull許容性を確認できます。たとえば、前のスクリーンショットでは、ツールは1行目のintsリスト(以前はintのリスト)がnull許容可能であると推論し、そのためint?のリストである必要があります。

移行結果の理解

#

各変更(または変更なし)の理由を確認するには、**提案された編集**ペインで対応する行番号をクリックしてください。理由は**編集の詳細**ペインに表示されます。

例として、null safety以前の次のコードを考えてみましょう。

dart
var ints = const <int>[0, null];
var zero = ints[0];
var one = zero + 1;
var zeroOne = <int>[zero, one];

このコードが関数外にある場合のデフォルトの移行(関数内では異なります)は後方互換性がありますが、理想的ではありません。

dart
var ints = const <int?>[0, null];
var zero = ints[0];
var one = zero! + 1;
var zeroOne = <int?>[zero, one];

**3行目**のリンクをクリックすると、移行ツールが!を追加した理由を確認できます。zeroがnullになることはないので、移行結果を改善できます。

移行結果の改善

#

分析で正しくないnull可能性が推論される場合は、一時的なヒントマーカーを挿入して、提案された編集を上書きできます。

  • 移行ツールの**編集の詳細**ペインでは、**/*?*/ヒントを追加**ボタンと**/*!*/ヒントを追加**ボタンを使用してヒントマーカーを挿入できます。

    これらのボタンはファイルにコメントをすぐに追加し、**元に戻すことはできません**。ツールが挿入したヒントが不要な場合は、通常使用しているコードエディターで削除できます。

  • ツールの実行中でも、エディターを使用してヒントマーカーを追加できます。コードはまだnull safetyに対応していないため、新しいnull safety機能を使用することはできません。ただし、null safety機能に依存しないリファクタリングなどの変更を行うことは可能です。

    コードの編集が完了したら、**ソースから再実行**をクリックして変更を取り込みます。

次の表は、移行ツールの提案された編集を変更するために使用できるヒントマーカーを示しています。

ヒントマーカー移行ツールへの影響
expression /!/移行されたコードに!を追加し、expressionを基になるnull許容しない型にキャストします。
type /!/typeをnull許容しない型としてマークします。
/*?*/前の型をnull許容可能型としてマークします。
/*late*/変数宣言をlateとしてマークし、遅延初期化を示します。
/*late final*/変数宣言をlate finalとしてマークし、遅延かつ1回限りの初期化を示します。
/*required*/パラメーターをrequiredとしてマークします。

1つのヒントは、コードの他の部分に波及効果を持つ可能性があります。前の例では、zeroに値が代入されている箇所(2行目)に/*!*/マーカーを手動で追加すると、移行ツールはzeroの型をint?ではなくintとして推論します。この型変更は、zeroを直接的または間接的に使用するコードに影響を与える可能性があります。

dart
var zero = ints[0]/*!*/;

上記のヒントを使用すると、移行ツールは提案された編集を変更します。次のコードスニペットに示すように、3行目にはzeroの後に!がなくなり、4行目ではzeroOneint?ではなくintのリストとして推論されます。

最初の移行ヒントを使用した移行
dart
var ints = const <int?>[0, null];
var zero = ints[0];
var one = zero! + 1;
var zeroOne = <int?>[zero, one];
dart
var ints = const <int?>[0, null];
var zero = ints[0]/*!*/;
var one = zero + 1;
var zeroOne = <int>[zero, one];

ファイルのオプトアウト

#

一度にすべてを移行することをお勧めしますが、特に大規模なアプリやパッケージでは、それが現実的ではない場合があります。ファイルまたはディレクトリをオプトアウトするには、緑色のチェックボックスをクリックします。後で変更を適用すると、オプトアウトされた各ファイルは、2.9 バージョンコメントを除いて変更されません。

増分移行の詳細については、不正確なnull safetyを参照してください。

完全に移行されたアプリとパッケージのみがDart 3と互換性があることに注意してください。

変更の適用

#

移行ツールが提案するすべての変更が適切であれば、**移行を適用**をクリックします。移行ツールはヒントマーカーを削除し、移行されたコードを保存します。また、ツールはpubspecの最小SDK制約を更新し、パッケージをnull safetyに対応させます。

次のステップは、コードを静的に分析することです。有効な場合は、コードをテストする必要があります。その後、pub.devにコードを公開している場合は、null安全なプリリリース版を公開する必要があります。

手動で移行する

#

移行ツールを使用しない場合は、手動で移行できます。

まず、**リーフライブラリを移行する**ことをお勧めします。リーフライブラリとは、パッケージの他のファイルを取り込まないライブラリです。次に、リーフライブラリに直接依存するライブラリを移行します。最後に、パッケージ内で最も多くの依存関係を持つライブラリを移行します。

たとえば、他の(null安全な)パッケージとコアライブラリを取り込むが、import '<local_path>'ディレクティブを持たないlib/src/util.dartファイルがあるとします。まずutil.dartを移行し、次にutil.dartのみに依存する単純なファイルを移行することを検討してください。ライブラリに循環インポートがある場合(たとえば、AがBを取り込み、BがCを取り込み、CがAを取り込む場合)、これらのライブラリをまとめて移行することを検討してください。

パッケージを手動で移行するには、次の手順に従います。

  1. パッケージのpubspec.yamlファイルを編集し、最小SDK制約を少なくとも2.12.0に設定します。

    yaml
    environment:
      sdk: '>=2.12.0 <3.0.0'
  2. パッケージ構成ファイルを再生成します。

    $ dart pub get

    少なくとも2.12.0の低いSDK制約でdart pub getを実行すると、パッケージ内のすべてのライブラリのデフォルトの言語バージョンが2.12以上に設定され、すべてnull safetyに対応します。

  3. IDEでパッケージを開きます。
    多くの分析エラーが表示される可能性があります。それは問題ありません。

  4. アナライザーを使用して静的エラーを特定し、各Dartファイルのコードを移行します。
    必要に応じて?!requiredlateを追加して、静的エラーを解消します。

コードを手動で移行する方法の詳細については、不正確なnull safetyを参照してください。

3. 解析する

#

パッケージを更新します(IDEまたはコマンドラインでdart pub getを使用)。次に、IDEまたはコマンドラインを使用して、コードの静的分析を実行します。

$ dart pub get
$ dart analyze     # or `flutter analyze`

4. テストする

#

コードが分析に合格したら、テストを実行します。

$ dart test       # or `flutter test`

null値を期待するテストを更新する必要がある場合があります。

コードに大規模な変更を加える必要がある場合は、再移行が必要になる可能性があります。その場合は、移行ツールを再度使用する前に、コードの変更を元に戻してください。

5. 公開する

#

移行後すぐにパッケージを公開することをお勧めします(プリリリース版として公開する場合もあります)。

パッケージのバージョンを更新する

#

破壊的変更を示すようにパッケージのバージョンを更新します。

  • パッケージが既に1.0.0以上である場合は、メジャーバージョンを増やします。たとえば、前のバージョンが2.3.2の場合は、新しいバージョンは3.0.0になります。

  • パッケージがまだ1.0.0に到達していない場合は、マイナーバージョンを増やすか、バージョンを1.0.0に更新します。たとえば、前のバージョンが0.3.2の場合は、新しいバージョンは0.4.0または1.0.0になります。

pubspecを確認する

#

パッケージの安定版null safetyバージョンを公開する前に、次のpubspecルールに従うことを強くお勧めします。

  • Dartの下位SDK制約を、テスト済みの最低安定バージョン(少なくとも2.12.0)に設定します。
  • すべての直接依存関係の安定版バージョンを使用します。

Null safetyへようこそ

#

ここまで来たら、完全に移行されたnull安全なDartパッケージが完成しているはずです。

依存するすべてのパッケージも移行されている場合、プログラムはnull参照エラーに関して健全です。コードを実行またはコンパイルすると、このような出力が表示されます。

Compiling with sound null safety

Dartチーム一同、コードの移行に感謝いたします。