DEV Community

Michele Volpato
Michele Volpato

Posted on • Updated on • Originally published at ishouldgotosleep.com

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

Discussion (0)