How do I add Methods or Values to Enums in Dart?

Dart

Dart Problem Overview


In Java when you are defining an enum, you can do something similar to the following, i.e. add members to an enum. Is this possible in Dart?

enum Foo {
  one(1), two(2);
  final num value;
  Foo(this.value);
}

Dart Solutions


Solution 1 - Dart

Starting with Dart 2.6 you can define extensions on classes (Enums included).

enum Cat {
  black,
  white
}

extension CatExtension on Cat {

  String get name {
    switch (this) {
      case Cat.black:
        return 'Mr Black Cat';
      case Cat.white:
        return 'Ms White Cat';
      default:
        return null;
    }
  }

  void talk() {
    print('meow');
  }
}

Example:

Cat cat = Cat.black;
String catName = cat.name;
cat.talk();

Here's one more live example (uses a constant map instead of a switch): https://dartpad.dartlang.org/c4001d907d6a420cafb2bc2c2507f72c

Solution 2 - Dart

Dart enums are used only for the simplest cases. If you need more powerful or more flexible enums, use classes with static const fields like shown in https://stackoverflow.com/a/15854550/217408

This way you can add whatever you need.

Solution 3 - Dart

Dart Enhanced Enum Classes

Starting with Dart 2.17, the Enhanced Enum Classes feature has been introduced. With that, the example from the question would look like this:

enum Foo {
  one(1),
  two(2);

  const Foo(this.value);
  final num value;
}

Now, you can just use the enum class like this:

void main() {
  const foo = Foo.one;
  print(foo.value); // 1
}

Note that you need to update your SDK constraint as the feature requires Dart 2.17:

environment:
  sdk: '>=2.17.0-0 <3.0.0'

Adding members

With enhanced enums, you can add any member to your enum as long as the constructor is const.

This also means that you can add getters or methods to existing enums, for example:

enum Cake {
  cherry,
  apple,
  strawberry;

  String get description => '$name cake';
}

Generics

Enhanced enum classes also enable you to use generics for you enums. If you combine this with members, you can do the following:

enum Bar<T extends Object> {
  number<int>(42),
  name<String>('creativecreatorormaybenot'),
  baz(true); // Note that type inference also works.

  const Bar(this.value);
  final T value;
}

Mixins and interfaces

In addition to declaring members, you can also mixin mixins and implement interfaces with enhanced enums and override any missing implementations.

mixin Foo {
  int get n;
}

abstract class Bar {
  void printNumber();
}

enum Baz with Foo implements Bar {
  one(1),
  two(2);
  
  const Baz(this.n);

  @override
  final int n;

  @override
  void printNumber() => print(n);
}

Multiple arguments

Finally note that even if I did not make use of it in any of the examples above, it is possible to have an arbitrary number of arguments (and an initializer list):

enum Foo {
  bar(42, description: 'The answer to life, the universe, and everything.'),
  baz(0, enabled: false, description: 'noop');

  const Foo(
    int number, {
    this.enabled = true,
    required this.description,
  }) : n = number;
  final int n;
  final bool enabled;
  final String description;
}

Solution 4 - Dart

Nope. In Dart, enums can only contain the enumerated items:

enum Color {
  red,
  green,
  blue
}

However, each item in the enum automatically has an index number associated with it:

print(Color.red.index);    // 0
print(Color.green.index);  // 1

You can get the values by their index numbers:

print(Color.values[0] == Color.red);  // True

See: https://www.dartlang.org/guides/language/language-tour#enums

Solution 5 - Dart

It may not be "Effective Dart" , I add a static method inside a Helper class ( there is no companion object in Dart) .

In your color.dart file

enum Color {
  red,
  green,
  blue
}

class ColorHelper{

  static String getValue(Color color){
    switch(color){
      case Color.red: 
        return "Red";
      case Color.green: 
        return "Green";
      case Color.blue: 
        return "Blue";  
      default:
        return "";
    }
  }

}

Since the method is in the same file as the enum, one import is enough

import 'package:.../color.dart';

...
String colorValue = ColorHelper.getValue(Color.red);

Solution 6 - Dart

extension is good, but it cannot add static methods. If you want to do something like MyType.parse(string), consider using a class with static const fields instead (as Günter Zöchbauer suggested before).

Here is an example

class PaymentMethod {
  final String string;
  const PaymentMethod._(this.string);

  static const online = PaymentMethod._('online');
  static const transfer = PaymentMethod._('transfer');
  static const cash = PaymentMethod._('cash');

  static const values = [online, transfer, cash];

  static PaymentMethod parse(String value) {
    switch (value) {
      case 'online':
        return PaymentMethod.online;
        break;
      case 'transfer':
        return PaymentMethod.transfer;
        break;
      case 'cash':
        return PaymentMethod.cash;
      default:
        print('got error, invalid payment type $value');
        return null;
    }
  }

  @override
  String toString() {
    return 'PaymentMethod.$string';
  }
}

I found this much handier than using a helper function.

final method = PaymentMethod.parse('online');
assert(method == PaymentMethod.online);

Solution 7 - Dart

I did this (inspired form the accepted answer by @vovahost)

enum CodeVerifyFlow {
  SignUp, Recovery, Settings
}

extension CatExtension on CodeVerifyFlow {
  String get name {
    return ["sign_up", "recovery", "settings"][index];
  }
}

// use it like
CodeVerifyFlow.SignUp.name

thank me later!

Solution 8 - Dart

As an improvement on the other suggestions of using Extensions, you can define your assigned values in a list or map, and the extension will be concise.

enum Numbers {
  one,
  two,
  three,
}

// Numbers.one.value == 1
// Numbers.two.value == 2
// Numbers.three.value == 3

example with list

extension NumbersExtensionList on Numbers {
  static const values = [1, 2, 3];
  int get value => values[this.index];
}

example with map

extension NumbersExtensionMap on Numbers {
  static const valueMap = const {
    Numbers.one: 1,
    Numbers.two: 2,
    Numbers.three: 3,
  };
  int get value => valueMap[this];
}

> Note: This approach has the limitation that you can not define a static factory method on the Enum, e.g. Numbers.create(1) (as of Dart 2.9). You can define this method on the NumbersExtension, but it would need to be called like NumbersExtension.create(1)

Solution 9 - Dart

There's an upcoming feature in Dart known as enhanced enums, and it allows for enum declarations with many of the features known from classes. For example:

enum Blah {
  one(1), two(2);
  final num value;
  const Blah(this.value);
}

The feature is not yet released (and note that several things are not yet working), but experiments with it can be performed with a suitably fresh version of the tools by passing --enable-experiment=enhanced-enums.

The outcome is that Blah is an enum declaration with two values Blah.one and Blah.two, and we have Blah.one.value == 1 and Blah.two.value == 2. The current bleeding edge handles this example in the common front end (so dart and dart2js will handle it), but it is not yet handled by the analyzer.

Solution 10 - Dart

For String returns :

enum Routes{
  SPLASH_SCREEN,
  HOME,
  // TODO Add according to your context
}

String namedRoute(Routes route){
  final runtimeType = '${route.runtimeTypes.toString()}.';
  final output = route.toString();
  return output.replaceAll(runtimeType, "");
}

Solution 11 - Dart

You can add extra fields and methods with my package enum_extendable.
It generates extensions on enum, so you can use your enum values in the similar way to instances of a regular Dart class.

For example, if you have enum MathOperator { plus, minus } the symbol and calculate(...) can be added to it.
So, the enum can be used in such way:

final n1 = 1;
final n2 = 2.0;
MathOperator.values.forEach((operator) {
  print('$n1 ${operator.symbol} $n2 = ${operator.calculate(n1, n2)}');
});

Usage:

  1. Add dependencies to pubspec.yaml:

    dependencies:
    enum_extendable_annotation:

    dev_dependencies:
    build_runner:
    enum_extendable_generator:

Install these dependencies:

# Dart
pub get

# Flutter
flutter packages get

2. Add imports to your enum file:

`import 'package:enum_extendable_annotation/enum_extendable_annotation.dart';`

part '<your enum file name>.enum_extendable.g.dart';

  1. Create a PODO class with fields and methods you wanted.
  2. Create a map with instances of this PODO class for each enum value.
  3. Annotate elements:
  • the enum with @ExtendableEnum();
  • the PODO class - @ExtendableEnumPodo();
  • the map of PODO instances - @ExtendableEnumValues().
  1. Run code generator:
  • if your package depends on Flutter:

    flutter pub run build_runner build

  • if your package does not depend on Flutter:

    dart pub run build_runner build

The file with extensions should be generated.

Example of the enum file:

import 'package:enum_extendable_annotation/enum_extendable_annotation.dart';

part 'math_operator.enum_extendable.g.dart';

@ExtendableEnum()
enum MathOperator { plus, minus }

@ExtendableEnumPodo()
class _MathOperatorPodo {

  final String symbol;
  final num Function(num, num) calculate;

  _MathOperatorPodo(
    this.symbol,
    this.calculate,
  );

  @ExtendableEnumValues()
  static final Map<MathOperator, _MathOperatorPodo> _values = {
  MathOperator.plus: _MathOperatorPodo(
     '+',
      (n1, n2) => n1 + n2,
    ),
  MathOperator.minus: _MathOperatorPodo(
      '-',
      (n1, n2) => n1 - n2,
    ),
  };
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDigital DeceptionView Question on Stackoverflow
Solution 1 - DartvovahostView Answer on Stackoverflow
Solution 2 - DartGünter ZöchbauerView Answer on Stackoverflow
Solution 3 - DartcreativecreatorormaybenotView Answer on Stackoverflow
Solution 4 - DartArgenti ApparatusView Answer on Stackoverflow
Solution 5 - DartRaymond ChenonView Answer on Stackoverflow
Solution 6 - DartEdwin LiuView Answer on Stackoverflow
Solution 7 - DartHemant_NegiView Answer on Stackoverflow
Solution 8 - DartBouke VersteeghView Answer on Stackoverflow
Solution 9 - DartErik ErnstView Answer on Stackoverflow
Solution 10 - DartCharles-Lévi BRIANIView Answer on Stackoverflow
Solution 11 - DartOlegView Answer on Stackoverflow