Enums

An enumeration type is a special class used to represent a fixed set of constant values.

All enums automatically inherit the Enum class. Enums are sealed types: they cannot be inherited, implemented, mixed in, nor instantiated explicitly by hand.

Abstract classes and mixins may explicitly implement or extend Enum, but you cannot create actual instances of such classes or mixins unless they are implemented or mixed into an enum declaration.

Define simple enums with the enum keyword by listing all enum constants:

enum Color { red, green, blue }

Trailing commas are permitted when declaring enums, which eases copy-paste operations and reduces coding mistakes.

Enhanced enums

Dart supports enhanced enums. You can define member fields, methods and constant constructors just like regular classes, yet instances are limited to predefined fixed constants.

Declaring enhanced enums comes with several mandatory constraints:

  1. All instance variables must be declared final (including variables introduced from mixins)
  2. Every generative constructor must be marked const
  3. Factory constructors can only return constant instances defined inside the enum
  4. No explicit inheritance from other classes (automatic inheritance from Enum)
  5. You cannot override index, hashCode, or the equality operator ==
  6. No member named values may be defined inside the enum; this conflicts with the auto-generated static values accessor
  7. All enum instances must appear at the very start of the enum definition, and at least one instance is required
  8. Within instance methods of enhanced enums, this refers to the current enum constant

Example

enum Vehicle implements Comparable<Vehicle> {
  car(tires: 4, passengers: 5, carbonPerKilometer: 400),
  bus(tires: 6, passengers: 50, carbonPerKilometer: 800),
  bicycle(tires: 2, passengers: 1, carbonPerKilometer: 0);

  const Vehicle({
    required this.tires,
    required this.passengers,
    required this.carbonPerKilometer,
  });

  final int tires;
  final int passengers;
  final int carbonPerKilometer;

  // Getter
  int get carbonFootprint => (carbonPerKilometer / passengers).round();
  bool get isTwoWheeled => this == Vehicle.bicycle;

  @Override
  int compareTo(Vehicle other) => carbonFootprint - other.carbonFootprint;
}Code language: Dart (dart)

Dart 3.13 and newer support primary constructors to simplify enhanced enum syntax:

enum Vehicle(
  final int tires,
  final int passengers,
  final int carbonPerKilometer,
) implements Comparable<Vehicle> {
  car(4, 5, 400),
  bus(6, 50, 800),
  bicycle(2, 1, 0);

  int get carbonFootprint => (carbonPerKilometer / passengers).round();
  bool get isTwoWheeled => this == Vehicle.bicycle;

  @Override
  int compareTo(Vehicle other) => carbonFootprint - other.carbonFootprint;
}Code language: Dart (dart)

Working with enums

Access enum constants the same way you access static variables:

final favoriteColor = Color.blue;
if (favoriteColor == Color.blue) {
  print('Your favorite color is blue!');
}Code language: Dart (dart)

The index property

Each enum constant comes with an index property returning its zero-based ordinal position inside the enum declaration:

assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);Code language: Dart (dart)

Static values constant

Use EnumName.values to retrieve a list containing all enum entries:

List<Color> colors = Color.values;
assert(colors[2] == Color.blue);Code language: Dart (dart)

Switch statements with enums

When using enums inside a switch block, the compiler emits warnings if you fail to cover all enum cases. You can add a default clause as fallback.

var aColor = Color.blue;

switch (aColor) {
  case Color.red:
    print('Red as roses!');
  case Color.green:
    print('Green as grass!');
  default:
    print(aColor); // Color.blue
}Code language: Dart (dart)

The name property

Call .name to obtain the string name corresponding to an enum constant:

print(Color.blue.name); // Outputs "blue"Code language: Dart (dart)

Access custom enum members

Enhanced enums allow you to access custom fields, getters and methods like ordinary objects:

print(Vehicle.car.carbonFootprint);Code language: CSS (css)

Below is a complete sample for this lesson. We will build an enum class for months that puts all knowledge above into practice.

enum Month implements Comparable<Month> {
  january(1, '一月', days: 31),
  february(2, '二月', days: 28),
  march(3, '三月', days: 31),
  april(4, '四月', days: 30),
  may(5, '五月', days: 31),
  june(6, '六月', days: 30),
  july(7, '七月', days: 31),
  august(8, '八月', days: 31),
  september(9, '九月', days: 30),
  october(10, '十月', days: 31),
  november(11, '十一月', days: 30),
  december(12, '十二月', days: 31);

  const Month(this.monthNumber, this.cnName, {required this.days});

  /// Gregorian calendar month number 1~12
  final int monthNumber;

  /// Name
  final String cnName;

  /// Days in common year
  final int days;

  /// Getter: Check if within Q1
  bool get isFirstQuarter => monthNumber <= 3;

  /// Getter: Check if month has 31 days
  bool get has31Days => days == 31;

  /// Custom method: Detect leap year February
  bool isLeapYearFebruary(int year) {
    if (this != Month.february) return false;
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
  }

  /// Implement Comparable for sorting
  @Override
  int compareTo(Month other) {
    return monthNumber - other.monthNumber;
  }
}

void main() {
  // 1. Basic access to enum constants
  Month current = Month.august;
  print('Current enum: $current');
  print('Enum name property: ${current.name}');
  print('Month: ${current.cnName}');
  print('Month number 1~12: ${current.monthNumber}');
  print('Days in common year: ${current.days}');
  print('Is 31-day month: ${current.has31Days}');
  print('Belongs to Q1: ${current.isFirstQuarter}');

  // 2. index property (zero-based index defined in enum)
  print('\n${Month.january.name} index = ${Month.january.index}');
  print('${Month.december.name} index = ${Month.december.index}');

  // 3. Fetch all enum entries via values
  List<Month> allMonths = Month.values;
  print('\nTotal ${allMonths.length} months');

  // 4. Using enums with switch
  print('\n==== switch check ====');
  switch (current) {
    case Month.january:
      print('Start of the year');
    case Month.february:
      print('May contain leap day');
    case Month.march:
    case Month.april:
    case Month.may:
      print('Spring');
    case Month.june:
    case Month.july:
    case Month.august:
      print('Summer');
    case Month.september:
    case Month.october:
    case Month.november:
      print('Autumn');
    case Month.december:
      print('End of the year, winter');
  }

  // 5. Call custom method
  Month feb = Month.february;
  print('\nLeap February in 2024: ${feb.isLeapYearFebruary(2024)}');
  print('Leap February in 2025: ${feb.isLeapYearFebruary(2025)}');

  // 6. Enum sorting via Comparable interface
  var selected = [Month.october, Month.january, Month.july];
  selected.sort();
  print('\nSorted months: ${selected.map((m) => m.cnName).toList()}');
}Code language: Dart (dart)

Execution output

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Current enum: Month.august
Enum name property: august
Month: 八月
Month number 1~12: 8
Days in common year: 31
Is 31-day month: true
Belongs to Q1: false

january index = 0
december index = 11

Total 12 months

==== switch check ====
Summer

Leap February in 2024: true
Leap February in 2025: false

Sorted months: [一月, 七月, 十月]Code language: JavaScript (javascript)

Enums

Previous:

Leave a Reply

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