Open7

Null Safety時代に必須(たぶん)のDart Extension

ピン留めされたアイテム
菊池紘菊池紘

便利なExtensionを集めていけたら良いなと思ってます。
ご意見も大歓迎!

菊池紘菊池紘

T.let

メソッドレシーバと引数を入れ替える手段がないと、optional chainingが機能しないケースがあるため。

extension LetExt<T> on T {
  R let<R>(R Function(T) block) => block(this);
}

使用例

someNullableValue?.let((value) => argMustBeNonNullMethod(value));

// letがない場合
if (someNullableValue != null) {
  argMustNonNullMethod(someNullableValue);
  // もしも someNullableValue が何かのメンバなら、 ! も必要になる。
  // argMustNonNullMethod(someNullableValue!);
}
菊池紘菊池紘

Iterable<T>.firstOrNull

https://zenn.dev/kikuchy/scraps/ed913ab0adc806#comment-1ba27f446d7655 に書いていただいた通り、 package:collectionIterableExtension を使用した方が良さそうです。
他にもいろいろな便利Extensionが含まれています。


以下、古い情報

Listなら isEmpry で確認できるが、mapとかでchainingしてるとそうもいかない。
「もし要素があれば後続の処理を呼ぶ。別に例外とか出さなくても良い」というケースはそこそこあるので、そこそこ使う。

extension FirstOrNullExt<T> on Iterable<T> {
  T? get firstOrNull {
    try {
      return first;
    } on StateError catch(_) {
      return null;
    }
  }
}

使用例

final numbers = [1, 3, 5, 7, 9, 11];

numbers
  .where((n) => n % 2 == 0)
  .firstOrNull?
  .let((even) => methodWantsFirstEvenNumber(even));
koji-1009koji-1009

dart-lang/collection にfirstOrNullは追加されていたりします。DartのFAQでfirstWhereOrNullの対応としてpackage:collectionを追加してねと書いてあるので、collection周りはpackage:collectionに一任してしまうのも良さそうです。

https://github.com/dart-lang/collection/blob/1.15.0/lib/src/iterable_extensions.dart#L263
https://dart.dev/null-safety/faq#the-iterablefirstwhere-method-no-longer-accepts-orelse---null

菊池紘菊池紘

おおおおお、知らなかったでした!!ありがとうございます!
他にもOrNull系が充実していて良いですね!

koji-1009koji-1009

migrationしようとすると、どうしても必要になるものがあるのでいい感じです!
おおよそほとんどの現場で必要だと思うので、次のDartのリリースで組み込まれるんじゃないかな……と思っていたりします。

菊池紘菊池紘

riverpod + state_notiriferを使い始めたら、Kotlinのalsoも欲しくなったので追加

extension AlsoExt<T> on T {
  T also(void Function(T it) func) {
    func(this);
    return this;
  }
}

createの中で他のStateNotifierにaddListenerしたいときとか、一度変数に取らなくて良いので楽。
ref.watch() で更新する手もあるけれど、インスタンスの作り直しになるので、インスタンスをDialogのコールバックとかで使いがちなStateNotifierとかには使いたくない。

final someProvider = StateNotifierProvider<SomeNotifier, SomeState>(
  (ref) => SomeNotifier().also((it) {
    it.addListener((state) {
      doSomethingWithState(state);
    });
  });
);