Extension Methods
Prerequisites: Classes and objects
An extension adds methods, getters, and operators to an existing
type — even one you didn't write, like String or int — without
changing or subclassing it.
Example
extension StringHelpers on String {
String get initials => split(' ')
.where((w) => w.isNotEmpty)
.map((w) => w[0].toUpperCase())
.join();
String capitalize() => isEmpty ? this : this[0].toUpperCase() + substring(1);
}
extension on int {
Duration get minutes => Duration(minutes: this);
}
void main() {
print('grace brewster hopper'.initials);
print('dart'.capitalize());
print(5.minutes);
}
Expected output
GBH
Dart
0:05:00.000000
extension StringHelpers on Stringadds members toString. Inside,thisis the string the method was called on, and its members can be used directly (splitmeansthis.split).- An extension without a name (
extension on int) is only usable in its own file. - Extensions must be imported to be used in other files, like anything else.
Printing a Duration shows hours, minutes, seconds, and microseconds.
Extensions on nullable types
extension on String? {
String orPlaceholder() => (this == null || this!.trim().isEmpty) ? '—' : this!;
}
void main() {
String? missing;
print(missing.orPlaceholder());
print('Ada'.orPlaceholder());
}
—
Ada
What extensions can't do
- They can't add fields (instance variables).
- They're resolved from the variable's static type at compile time,
so they don't work on
dynamicvalues and can't override a class's own methods.
Common mistakes
- Adding very general names to common types. Keep extension names specific, so they don't clash with other packages or future Dart versions.