We are migrating our Flutter app into null safety and I've encountered a bunch of missing helpers in order to get rid easily of an optional into a non-optional of the same type.
To get you in the context, I would like to have a
List<String?> optionalList = ['hi', 'hola', null];
and similar to compactMap()
in Swift, I would like to have a function that can convert any map into a map that excludes the null items and only return a list of non-optional items
ex:
final List<String> newNonOptionalList = optionalList.compactMap((item) => item.toUpperCase());
// newNonOptionalList = ['HI', 'HOLA']
I'm trying to make a helper for these kinds of cases, including many others I found valuable for Dart.
Does anyone have an idea of why it is not working, this is a little of what I've tried so far:
extension ListNullSafetyExtension<T> on List<T?>? {
Iterable<R> compactMap<R>(R Function(T element) convert) sync* {
for (var element in this.removeNulls()) {
if (element != null) yield convert(element);
}
}
List<T> removeNulls() {
if (this == null) return [];
this!.removeWhere((value) => (value == null));
return List.from(this!).whereType<T>().toList();
}
}
Even though this does remove the nulls and executes the map, it always returns the same optional type in the list, meaning it doesn't unwrap it and removeNulls()
returns a List<dynamic>
instead of a List<the_type_I_used>
I would really appreciate your help in understanding why these 2 functions never change their type since I can only find very basic generics posts of the topic.
You can easily collapse a List<T?>
to a List<T>
with null
elements filtered out by using Iterable.whereType<T>()
:
List<String?> optionalList = ['hi', 'hola', null];
List<String> newNonOptionalList = optionalList.whereType<String>().toList();
If you really want your own extension method (even though it doesn't add much):
extension IterableNullSafetyExtension<T> on Iterable<T?>? {
Iterable<T> removeNulls() => this?.whereType<T>() ?? [];
}
Additionally, one thing wrong with your attempted implementation is that ListNullSafetyExtension<T>
is already generic and parameterized on T
. When you later try to add an extension method:
List<T> removeNulls<T>() {
That extra <T>
at the end makes removeNulls
generic again, using a T
that's independent of the T
from ListNullSafetyExtension
. Don't do that.
Also see: How to convert a List<String?> to List in null safe Dart? Stack Overflow