Skip to content
AgileLogics
5 min read

Extension Types

Prerequisites: Extension methods, Class modifiers

An extension type (Dart 3.3+) wraps an existing type to give it a new compile-time identity and its own API — with no runtime cost. At runtime, the wrapper disappears and only the underlying value remains.

Preventing mix-ups

extension type UserId(int value) {}
extension type OrderId(int value) {}

String findOrder(OrderId id) => 'Order #${id.value}';

void main() {
  final order = OrderId(42);
  print(findOrder(order));
  print(order);
}
Order #42
42

Passing a UserId to findOrder is a compile error, even though both are "just an int" underneath:

extension type UserId(int value) {}
extension type OrderId(int value) {}

String findOrder(OrderId id) => 'Order #${id.value}';

void main() {
  print(findOrder(UserId(7)));
}
hello.dart:7:19: Error: The argument type 'UserId' can't be assigned to the parameter type 'OrderId'.

print(order) prints 42 — at runtime the value really is just an int, so no extra object is created.

Adding a focused API

Extension types can add methods and hide the underlying type's members:

extension type Celsius(double degrees) {
  Celsius operator +(Celsius other) => Celsius(degrees + other.degrees);
  double get fahrenheit => degrees * 9 / 5 + 32;
  bool get isFreezing => degrees <= 0;
}

void main() {
  final today = Celsius(21.5);
  final warmer = today + Celsius(3);
  print(warmer.degrees);
  print(warmer.fahrenheit);
  print(Celsius(-2).isFreezing);
}
24.5
76.1
true

A Celsius exposes only what makes sense for temperatures — you can't accidentally call .round() or add a plain number.

Extension types vs classes

  • An extension type is purely a compile-time layer. Checks like value is Celsius look at the underlying type at runtime, so they can't tell a Celsius from any other double.
  • A class creates a real object, with its own runtime identity.

Use extension types for zero-cost wrappers — IDs, units, and typed views over JSON maps — and classes for everything else. They're also central to Dart's modern JavaScript interop.