atreeon
atreeon

Reputation: 24157

Dart - Constrain a generic type (T) to an Enum

Is there a way to constrain a generic type to be an enum, something like the following?

class MyClass<T extends enum> {}

Something like this in C#.

Upvotes: 38

Views: 10200

Answers (4)

Brian Lacy
Brian Lacy

Reputation: 19118

I've been using this simple extension method adapted from @JCKödel's answer:

extension StringToEnumExtension on String {
  TEnum toEnumValueOrNull<TEnum extends Enum>(List<TEnum> values) =>
    values.firstWhereOrNull(
      (v) => v.name == this,
    );
}

The catch is, of course, you have to provide the "values" explicitly:

// Sample Enum
enum RecordStatus {
  active,
  archived,
  deleted
}

// Arbitrary string value
String someValue = 'active';

// Convert it
RecordStatus someStatus =
  // Pass the Enum's values explicitly to the method
  someValue.toEnumValueOrNull(RecordStatus.values) ??
  // Fallback, in case the string doesn't match
  RecordStatus.active;

It's not ideal for every case, but it works as long as you know what enum you're converting it to.

Upvotes: 1

Dinesh
Dinesh

Reputation: 1820

Adding some extra context to @xbalaj answer. This is how you can pass enums as generics.


enum Fruits {
 apple,
 orange,
 banana
}

enum Numbers {
 one,
 two,
 three
}

void main() {
   print("Numbers:");
   var numberEnums = MyClass<Numbers>(Numbers.values); 
   print("Fruits:");
   var fruitEnums = MyClass<Fruits>(Fruits.values);
}

class MyClass<T extends Enum> {
  List<T> myEnum;

  MyClass(this.myEnum) {
   print(myEnums);

   for (final e in myEnums) {
     if (e is Numbers) {
      // Do something specific to numbers
     } 

     if (e is Fruits) {
     // Do something specific to fruits
     }
   }

  }

}

Output:

Numbers: 
[Numbers.one, Numbers.two, Numbers.three]
Fruits:
[Fruits.Fapple, Fruits.orange, Fruits.banana]

Upvotes: 1

xbalaj
xbalaj

Reputation: 1067

It is now possible to constrain a generic type to an Enum since Dart 2.16.

You can do so in a following way:

class MyClass<T extends Enum> {}

Now you can pass to the generic parameter T of MyClass only enum.

Upvotes: 33

JCK&#246;del
JCK&#246;del

Reputation: 780

It is not possible in Dart. I had the same issue converting enum properties to a SQLite database (which can hold only its numeric types), so I needed enum.values to "parse" the integer to enum and enum.index to convert the enum value to an int.

The only way possible is to cast the enum to dynamic or passing the enum values.

Example:

T mapToEnum<T>(List<T> values, int value) {
  if (value == null) {
    return null;
  }

  return values[value];
}

dynamic enumToMap<T>(List<T> values, T value) {
  if (value == null) {
    return null;
  }

  return values.firstWhere((v) => v == value);
}

So I can use like this:

final SomeEnum value = SomeEnum.someValue;
final int intValue = enumToMap(SomeEnum.values, value);
final SomeEnum enumValue = mapToEnum(SomeEnum.values, value.index);

Upvotes: 15

Related Questions