32

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#.

creativecreatorormaybenot
  • 114,516
  • 58
  • 291
  • 402
atreeon
  • 21,799
  • 13
  • 85
  • 104
  • I don't think so, there is no superclass for enums: https://github.com/dart-lang/sdk/issues/21712#issuecomment-461422408 – Frank Treacy Dec 16 '19 at 21:51
  • The only thing you could do with this constraint is call `values` on the object `T`, which you could do anyway by treating the object as `dynamic`. I can't imagine what other benefit you would get from this constraint (with Dart enums, anyway). – Abion47 Dec 16 '19 at 23:50
  • 2
    The application is to convert enum from/to a map, for instance, saving in a sqlite database. Instead of asking why, just answer the question or say "I don't know". And, yes, dynamic is the only way to access enum.values and enum.index, the two enum properties to convert an enum value without mirror (which is unavailable on Flutter) – JCKödel Feb 28 '20 at 22:05
  • 2
    A case where this would be beneficial, for me at least, is making generic extensions restricted to enums. I could write generic extensions for all types and it will include enums. But I don't want to apply the extension to everything. I wish this was supported. – Vimtekken Jun 23 '21 at 00:10

3 Answers3

27

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.

xbalaj
  • 977
  • 1
  • 8
  • 14
  • 3
    Great feature but, still, using _values_ out of _T_ doesn't seem to be possible: `T stuff(String s) { return T.values.firstWhere((e) => e.toString() == s); }` doesn't work: error message is that the getter _values_ is not defined etc. – Jacques Apr 03 '22 at 19:46
  • Hi @Jacques, I think Enum refers to only one value of the enum type. i.e, You can access two properties: the index and the name of the value. – Jose Enrique Pons Frias Apr 04 '22 at 07:00
  • 1
    @José Enrique Pons Fias. I think you are missing something. Given `enum Fruit { banana, apple}`, you're allowed to write `Fruit.values`. I opened a [ticket](https://github.com/dart-lang/sdk/issues/48736) at _github.com/dart-lang_. It appears that my comment makes sense, and that is related to another brainstorming. It is just not supported so far by Dart. – Jacques Apr 04 '22 at 14:36
  • 1
    the Enum class, as it is implemented, only represent a value of your enum. In this case, either banana or apple. But it doesn't represent the Fruit enum. That makes sense. I.e: myFunction(String aString), aString is a specific String, not all the possible values of a String. Having all the possible values for an Enum would be useful though. – Jose Enrique Pons Frias Apr 04 '22 at 14:58
13

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);
JCKödel
  • 723
  • 9
  • 19
0

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]
Dinesh
  • 1,711
  • 2
  • 20
  • 41
  • The generic class "MyClass" checks explicitly for concrete enum types (Numbers / Fruits) instead of T, defeating the whole purpose of trying to use generics. – marcos E. Jun 13 '23 at 15:58
  • That is a limitation of dart. That is how currently you can use an Enum in generics. – Dinesh Jun 13 '23 at 17:16