Extension methods for generic types

mvolpato

Michele Volpato

Posted on June 15, 2021

Extension methods for generic types

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
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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>.

💖 💪 🙅 🚩
mvolpato
Michele Volpato

Posted on June 15, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related