Yesterday I made a quick update to my app. All the code compiled and all the tests succeeded, so I published an update. This morning, I wake up to a half broken app. What happened?

The simplified snippet was:

await Firebase.initializeApp();
final instance = FirebaseFirestore.instance;
final transformer = StreamTransformer.fromHandlers(
    handleData: (snapshot, sink) {
  sink.add(40);
});
final stream =
    instance.collection('temperatures').snapshots();
final numberStream = stream.transform<int>(transformer);
await for (var snapshot in numberStream) {
  print(snapshot);
}

The code converts each temperature document to the hardcoded number 40. The code compiles fine. But when I ran it, the error was:

_TypeError (type '_StreamHandlerTransformer<dynamic, dynamic>' is not a subtype of type 'StreamTransformer<QuerySnapshot<Map<String, dynamic>>, int>')

I wish that my Firestore testing library (https://pub.dev/packages/fake_cloud_firestore) had caught it. So I went into the code and tried to write the failing unit test. This time, the compiler complained right away:

In this project, the compiler correctly throws a compilation error

What was different? I came back to the project where I had experienced the runtime error, and the main difference is, it evaluated transformer's type to be StreamTransformer<dynamic, dynamic>.

In the project where the compiler didn't throw a compilation error

The difference was in the project's sdk version. The project in which the compiler didn't catch the issue was prior to 2.12, while the newer one caught the error directly. This has nothing to do with null safety. Yet 2.12 probably introduced some better type checking. I had read something about "strong mode", but the article mentioned Dart 2 without being explicit. In the Dart 2.12 release notes, I don't see anything that could explain this improvement in the type checks.

Anyhow, this is a strong push for me to switch the environment to 2.12 to all of my Flutter projects. The issue though is that it'll also force me to resolve all compilation errors due to null safety.