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, R> 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<T>() {
if (this == null) return [];
final newList = [...this!];
newList.removeWhere((value) => (value == null));
List<T> listWithoutNulls = newList.map((e) => e!).toList() as List<T>;
return listWithoutNulls;
}
}
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.
CodePudding user response:
You can add those options in your analysis_options.yaml
file (if it does not exist, create it at the same level as you pubspec.yaml
):
analyzer:
language:
strict-inference: true
strict-raw-types: true
strong-mode:
implicit-casts: false
implicit-dynamic: false
Then run flutter pub get
and you should get warning when omitting the types (not in every case but it should cover the ones where omissions might be dangerous).
Other lints can be used to be even more restrictive such as always_specify_types
but I find this one a bit too much. In any case, if what I provided does not suit you, you should search for lints that can enable the warnings you want.
CodePudding user response:
change this:
final List<String> newNonOptionalList = optionalList.compactMap((item) => item.toUpperCase());
to this
final List<String> newNonOptionalList = optionalList.compactMap((item) => item.toUpperCase()).toList();
CodePudding user response:
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