The 3 new lints in Dart 2.18

Alexey Inkin
Flutter Senior
Published in
3 min readSep 2, 2022

Dart 2.18 is out on Aug 30, and here you can read what it brings. What that article is missing is that is has some new lints.

discarded_futures

If a method is asynchronous, its future is meant to notify your code that some change has happened. The linter documentation has a good example when this is vital:

void recreateDir(String path) {
deleteDir(path);
createDir(path);
}

Future<void> deleteDir(String path) async { /* ... */ }

Future<void> createDir(String path) async { /* ... */ }

If the future of the first call is not awaited, then the second call will throw an error.

Dart already had unawaited_futures lint that was flagging such issues in async functions, but the example above was not covered by it because recreateDir is synchronous.

The new discarded_futures lint fills the missing gap and covers synchronous code.

It is not a replacement of the older lint, you should enable both of them.

Ideally, you should await or return all futures so that the client code has a chance to decide if it wants to await the result, but this is not always possible. For instance, a state of a StatefulWidget in Flutter has a synchronous dispose() method, so all futures created there are discarded. In this case use unawaited function like this:

@override
void dispose() {
unawaited(_streamController.close());
}

unnecessary_to_list_in_spreads

This code works:

final list = [
1,
2,
...[-1, 3, 4].where((n) => n > 0).toList(),
];

However, toList() is useless in this case, because where returns an Iterable, and the spread operator ... also accepts a Iterable. The list is thus created just to be disposed.

The new unnecessary_to_list_in_spreads lint flags such code.

unnecessary_null_aware_operator_on_extension_on_nullable

Now this one reveals a feature of Dart you likely did not know about. You can write an extension on a nullable type, call its method on a null and witness this being null:

void main() {
int? n;
n.printThis();
}
extension on int? {
void printThis() {
print(this); // Prints 'null'
}
}

If you change the call to this,

n?.printThis();  // Added '?'

… then the method will not be called, and nothing will be printed.

The new unnecessary_null_aware_operator_on_extension_on_nullable lint forces you to call such methods without ? and to move the null check into the method.

Why? Well, since you put it into an extension on nullable, you must have a point of calling it on null. Otherwise you should just add a similar extension on a non-nullable type.

Calling methods on null is actually useful in Dart. The most common example is this:

final a = null;
final str = a.toString(); // 'null'

Here is one real-world example:

extension on String? {
bool get isNullOrEmpty {
var self = this;
return self == null || self.isEmpty;
}
}

Enabling the New Lints

Read this article on how to enable those new lints manually.

Alternatively, you can use my package total_lints which enables most of the lints for your project. I use it to avoid repeating the linter configuration for my projects.

--

--

Alexey Inkin
Flutter Senior

Google Developer Expert in Flutter. PHP, SQL, TS, Java, C++, professionally since 2003. Open for consulting & dev with my team. Telegram channel: @ainkin_com