Extension methods

Extension methods let you add new functionality to existing types and third-party library types without modifying the source code of the original class. Your IDE’s autocompletion will list extension methods alongside native methods.

You cannot alter APIs provided by others, yet you want to add convenient helper methods.

Sample requirement: Use '42'.parseInt() instead of int.parse('42').

Syntax Structure

extension ExtensionName? on TargetType {
  // Methods, getters, setters, operators, static members
}Code language: JavaScript (javascript)

Example

// Place everything in a single file, no separation required; main runs directly
extension NumberParsing on String {
  int parseInt() {
    return int.parse(this);
  }

  double parseDouble() {
    return double.parse(this);
  }
}

void main() {
  print('42'.parseInt());       // 42
  print('3.14'.parseDouble());  // 3.14
  print('100'.padLeft(6));      // Compare with built-in String method
}Code language: Dart (dart)

Output

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
42
3.14
   100Code language: CSS (css)

The extension name is optional; this refers to the instance invoking the extension.

Supported Member Types for Extensions

Inside an extension you may define: instance methods, getters, setters, operators and static members.

extension StringExt on String {
  // getter
  bool get isEmptyOrBlank => trim().isEmpty;

  // Instance method
  String repeat(int count) => List.filled(count, this).join();

  // Operator overloading
  String operator *(int count) => repeat(count);

  // Static member (accessed via extension name)
  static String emptyStr = '';
  static void printTip() => print("Static method of string extension");
}

void main() {
  var str = " dart ";
  print(str.isEmptyOrBlank);
  print("hi" * 3);
  print("hello".repeat(2));

  // Access static members
  print(StringExt.emptyStr);
  StringExt.printTip();
}Code language: PHP (php)

Execution Result

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
false
hihihi
hellohello

Static method of string extensionCode language: PHP (php)

Unnamed Extensions (Anonymous Extensions)

Omit the extension name, making it visible only within the current library. Conflicts cannot be resolved with explicit invocation.

You cannot invoke it externally using the syntax ExtensionName(instance).

extension on String {
  bool get isBlank => trim().isEmpty;
}

void main() {
  print("   ".isBlank); // true
}Code language: Dart (dart)

Static members inside anonymous extensions can only be used within the extension itself.

Generic extensions

You can create extensions for generic types such as List<T>

extension MyFancyList<T> on List<T> {
  int get doubleLength => length * 2;
  List<T> operator -() => reversed.toList();
  List<List<T>> split(int at) => [sublist(0, at), sublist(at)];
}

void main() {
  List<int> list = [1, 2, 3, 4];
  print(list.doubleLength);          // 8
  print(-list);                      // [4,3,2,1]
  print(list.split(2));              // [[1,2],[3,4]]
}Code language: Dart (dart)

Execution Result

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
8
[4, 3, 2, 1]
[[1, 2], [3, 4]]Code language: CSS (css)

Static Types vs dynamic

dynamic variables cannot call extension methods

Extension methods are resolved statically. The type of a dynamic variable is determined at runtime, so extensions cannot be located:

void main() {
  dynamic d = '2';
  // print(d.parseInt()); // Throws NoSuchMethodError at runtime

  var v = '2';
  print(v.parseInt()); // Type inferred as String, works normally
}

extension NumberParsing on String {
  int parseInt() => int.parse(this);
}Code language: JavaScript (javascript)

Reason: Extension methods bind based on the variable’s static type during compilation, not through runtime lookup.

Solutions for API Name Conflicts

Three approaches exist when multiple extensions contain identically named members.

1: Hide conflicting extensions using show / hide on import

// string_apis.dart contains NumberParsing
// string_apis_2.dart contains NumberParsing2, which also defines parseInt
import 'string_apis.dart';
import 'string_apis_2.dart' hide NumberParsing2;

void main() {
  print('42'.parseInt()); // Uses implementation from string_apis.dart
}Code language: Dart (dart)

2: Explicitly call the extension (wrapper syntax)

import 'string_apis.dart';    // NumberParsing
import 'string_apis_2.dart';  // NumberParsing2

void main() {
  // print('42'.parseInt()); // Conflict, compile error
  print(NumberParsing('42').parseInt());
  print(NumberParsing2('42').parseInt());
}Code language: Dart (dart)

3: Import libraries with prefixes

Use prefixes to distinguish extensions with identical names:

import 'string_apis.dart';
import 'string_apis_3.dart' as rad;

void main() {
  print(NumberParsing('42').parseInt());
  print(rad.NumberParsing('42').parseInt());

  // Non-conflicting extension methods can still be invoked implicitly
  print('42'.parseNum());
}Code language: Dart (dart)

Extension methods

Previous:

Leave a Reply

Your email address will not be published. Required fields are marked *