Extension methods for generic types
Michele Volpato
Posted on June 15, 2021
Since Dart 2.7 it is possible to add functionalities to existing libraries. If a class is missing a method you would like to use, you can just extend that class with your own implementation of such a method.
You do not need to create a pull request on the code of the library you want to update, you can keep the new functionality locally to your code. For example, if you need to format a Duration
so that it shows days, hours, minutes, and seconds in the following format: dd:HH:MM:SS
, you can define an extension method on Duration
:
extension DurationFormatter on Duration {
/// Returns a day, hour, minute, second string representation of this `Duration`.
///
///
/// Returns a string with days, hours, minutes, and seconds in the
/// following format: `dd:HH:MM:SS`. For example,
///
/// var d = new Duration(days:19, hours:22, minutes:33);
/// d.dayHourMinuteSecondFormatted(); // "19:22:33:00"
String dayHourMinuteSecondFormatted() {
this.toString();
return [
this.inDays,
this.inHours.remainder(24),
this.inMinutes.remainder(60),
this.inSeconds.remainder(60)
].map((seg) {
return seg.toString().padLeft(2, '0');
}).join(':');
}
}
void main() {
var d = Duration(days:19, hours:22, minutes:33);
print(d.dayHourMinuteSecondFormatted()); // 19:22:33:00
}
Extension on generic types
You can not only extend a "concrete" type like Duration
. You can also extend the functionalities of a generic type, so that all its concrete instances (and all subclasses) obtain the new extension method.
For instance, if we want to add a firstWhereOrNull
to List
, where we either return the first element in the list that satisfies a condition, or null
if none satisfies that condition, we can create an extension method like this:
extension FirstWhereOrNull<E> on Iterable<E> {
/// Returns the first element that satisfies the given predicate test.
///
/// Iterates through elements and returns the first to satisfy test.
/// If none is found, returns `null`.
E? firstWhereOrNull(bool test(E element)) {
for (E element in this) {
if (test(element)) return element;
}
return null;
}
}
void main() {
final List<String> myList = ["First", "Second", "Third"];
print(myList.firstWhereOrNull((element) =>
element.endsWith('d'))); // Second
print(myList.firstWhereOrNull((element) =>
element.startsWith('d'))); // null
}
By creating the extension method on the generic Iterable<E>
we add it to all concrete types of all subclasses of Iterable
, like Queue, List, and Set, thus also to List<E>
.
Posted on June 15, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.