Los enhanced enums transforman un simple listado de nombres en tipos con verdadera capacidad de modelado. Un enum en Dart es, en esencia, una clase con restricciones: no puedes instanciarlo fuera de sus valores definidos, pero puedes dotar a cada valor de campos, métodos y getters. Esto es posible porque Dart permite definir constructores const para ellos, lo que garantiza que cada valor sea una instancia única e inmutable disponible en tiempo de compilación.
¿Cuándo deberías usarlos? Cuando tus constantes no son solo etiquetas, sino que representan entidades con datos asociados. Por ejemplo, un estado de pedido que no solo se llama shipped, sino que tiene un código de error o una prioridad. Si intentas usar un enum tradicional para esto, terminarás con funciones switch dispersas por todo tu código para “traducir” el enum a su valor real. Al usar enhanced enums, encapsulas esa lógica dentro del propio tipo. Si intentas declarar un campo que no sea final o un constructor que no sea const, el compilador fallará, ya que la integridad del modelo depende de que los valores del enum sean inmutables y predecibles.
/// Representa el estado de una transacción financiera.
enum TransactionStatus implements Comparable<TransactionStatus> {
pending(100, 'Pendiente'),
processing(200, 'En proceso'),
completed(300, 'Completado'),
failed(400, 'Fallido');
// Los campos deben ser final porque los valores son constantes.
final int code;
final String label;
// El constructor debe ser const para que los valores sean constantes.
const TransactionStatus(this.code, this.label);
// Un getter para lógica de negocio interna.
bool get isFinal => this == TransactionStatus.completed ||
this == TransactionStatus.failed;
// Sobrescribir toString para mejorar logs y depuración.
@override
String toString() => '$label (ID: $code)';
// Implementación de Comparable para permitir ordenamiento basado en el código.
@override
int compareTo(TransactionStatus other) => code.compareTo(other.code);
}
void main() {
final status = TransactionStatus.completed;
print('Estado actual: $status');
print('¿La transacción terminó? ${status.isFinal}');
// Gracias a Comparable, podemos ordenar una lista de estados.
final statuses = [
TransactionStatus.failed,
TransactionStatus.pending,
TransactionStatus.completed,
TransactionStatus.processing,
];
statuses.sort();
print('Estados ordenados por prioridad:');
for (var s in statuses) {
print(' - $s');
}
}
En el código anterior, hemos definido TransactionStatus no solo como un tipo, sino como un modelo de datos. Al declarar final int code y final String label, estamos permitiendo que cada constante (pending, processing, etc.) guarde su propia información. Cuando llamas a status.isFinal, no estás ejecutando un switch externo, sino accediendo a una propiedad que vive dentro de la lógica del tipo.
El uso de implements Comparable<TransactionStatus> es clave: le estamos diciendo al runtime que este enum puede compararse consigo mismo. Esto permite que el método statuses.sort() funcione correctamente, utilizando la lógica de compareTo que definimos internamente para comparar los valores de code. Al sobreescribir toString(), garantizamos que print(status) devuelva algo útil para un humano (Completado (ID: 300)) en lugar de la simple cadena TransactionStatus.completed, lo cual es fundamental para el debugging en entornos de producción.
El error frecuente
Un error común al migrar de clases normales a enhanced enums es intentar declarar campos que no sean final. En una clase estándar, podrías querer cambiar un valor en tiempo de ejecución, pero en un enum esto es imposible porque sus instancias son constantes de tiempo de compilación.
// ❌ ERROR DE COMPILACIÓN
enum ErrorEnum {
bad(1),
good(2);
int value; // Error: Non-final field in an enum
const ErrorEnum(this.value);
}
// ❌ ERROR DE COMPILACIÓN
enum AnotherError {
val(1);
final int value;
AnotherError(this.value); // Error: Non-const constructor
}
Si necesitas un objeto que cambie su estado, no uses un enum; usa una class. El enum debe ser estrictamente para conjuntos de valores fijos y sus datos asociados deben ser inmutables.
N° 58