Dart - Enhanced Enums with Members Examples

Just like many programming languages, Dart allows you to create enums for defining finite sets of values. Sometimes, you may want to add fields or functions to your enum. For example, there is an enum consisting of possible statuses and each status has a unique code. That wasn't possible until Dart 2.17, which introduced enhanced enums with members.

Creating Enhanced Enum with Members

Below is a basic enum without any members.

  enum Status {
    pending,
    success,
    failed,
    ;
  }

We are going to add a field code to the enum. To do so, first we have to add the field to the enum (just like adding a field to a class in Dart). We also need to create a constructor with the field as the parameter and each defined enum value has to be defined by calling the constructor.

  enum Status {
    pending(1),
    success(2),
    failed(3),
    ;

    final int code;

    const Status(this.code);
  }

In the example above, the code field is final, which means it has to be initialized. It doesn't allow null values as well. If you want to allow null values, just make the field nullable by adding ? after the type (e.g. int?).

You can have more than one field on your enum. In addition, you can also create your functions, like the example below.

  enum Status {
    pending(1, false),
    success(2, true),
    failed(3, true),
    ;
  
    final int code;
    final bool isFinal;
  
    const Status(this.code, this.isFinal);
  
    String getUpperCaseName() {
      return name.toUpperCase();
    }
  }

Finding Enum by Field Value

In some cases, we want to get an enum value based on its field value. For example, we want to get the Status enum above by using the given code value. For that purpose, just create a function which accepts the field value as the parameter. Inside the function, iterate over the possible values which can be obtained from the values field.

  enum Status {
//...
    static Status? getByCode(int code) {
      for (Status status in Status.values) {
        if (status.code == code) {
          return status;
        }
      }

      return null;
    }
//...
  }

However, the above code is not efficient since it will iterate over the values everytime the function is called. The solution is by caching the values to a Map.

  enum Status {
//...
    static final Map<int, Status> byCode = {};

    static Status? getByCode(int code) {
      if (byCode.isEmpty) {
        for (Status status in Status.values) {
          byCode[status.code] = status;
        }
      }

      return byCode[code];
    }
//...
  }

Full Code

enum/status.dart

  enum Status {
    pending(1, false),
    success(2, true),
    failed(3, true),
    ;
  
    final int code;
    final bool isFinal;
  
    static final Map<int, Status> byCode = {};
  
    const Status(this.code, this.isFinal);
  
    static Status? getByCode(int code) {
      if (byCode.isEmpty) {
        for (Status status in Status.values) {
          byCode[status.code] = status;
        }
      }
  
      return byCode[code];
    }
  
    String getUpperCaseName() {
      return name.toUpperCase();
    }
  
    @override
    String toString() {
      return "$name($code)";
    }
  }

main.dart

  import 'package:dart/enum/status.dart';
  
  void main() {
    print(Status.success.getUpperCaseName()); // SUCCESS
    print(Status.success.toString()); // success(2)
    print(Status.getByCode(1)); // pending(1)
  } 

Summary

That's how to use enhanced enum with members in Dart 2.17. If your Dart version is below 2.17, you have to upgrade it or use Dart extensions instead.