Extension Methods and Extension Types

17.1 Extension Methods

Extensions are statically resolved (based on the static type). They don't work on dynamic values. Resolve conflicts with StringX('x').capitalize() or hide/show imports.

extension StringX on String {
  bool get isValidEmail => RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$').hasMatch(this);
  String capitalize() => isEmpty ? this : '${this[0].toUpperCase()}${substring(1)}';
  String truncate(int max) => length <= max ? this : '${substring(0, max)}…';
}

extension NumX on num {
  Duration get seconds => Duration(milliseconds: (this * 1000).round());
}

extension ListSum on Iterable<num> {
  num get total => fold(0, (a, b) => a + b);
}

extension<T> on List<T> {                 // unnamed (private to the file)
  T? get secondOrNull => length > 1 ? this[1] : null;
}

void main() {
  print('[email protected]'.isValidEmail);
  print('dart'.capitalize());
  print(2.5.seconds);
  print([1, 2, 3].total);
}

17.2 Extension Types (Dart 3.3)

Uses: type-safe IDs and units, wrapping JS interop types (package:web uses extension types), zero-overhead API views over existing types.

Unlike classes, extension types have no runtime representation: is/as checks see the underlying type.

extension type UserId(int value) {                    // zero-cost wrapper (erased at runtime)
  UserId.parse(String s) : value = int.parse(s);
  bool get isValid => value > 0;
}

extension type Email._(String value) implements String {   // can expose the underlying type's members
  factory Email(String raw) {
    if (!raw.contains('@')) throw FormatException('Invalid email: $raw');
    return Email._(raw.toLowerCase());
  }
}

void sendTo(Email email) => print('Sending to $email');

void main() {
  final id = UserId(42);
  print(id.isValid);
  // int raw = id;                 // ❌ not assignable without .value (unless it implements int)
  final email = Email('[email protected]');
  sendTo(email);
  print(email.length);             // String members available via `implements String`
  // sendTo('[email protected]');     // ❌ compile error: type safety without runtime cost
}