Dart: Enums, Extension Methods and Records

Three features that make Dart more expressive than a traditional enum

🪐 1. Enhanced Enum (with data and methods)

Result:

Planeta.jupiter.gravedad
2.36
pesoEn(70)
165.2 kg in Jupiter

Choose a planet

enum Planeta {
  mercurio(gravedad: 0.378),
  marte(gravedad: 0.377),
  jupiter(gravedad: 2.360),
  neptuno(gravedad: 1.140);

  const Planeta({required this.gravedad});
  final double gravedad;

  double pesoEn(double pesoTierra) => pesoTierra * gravedad;
}

print(Planeta.jupiter.pesoEn(70)); // 165.2
💡 Enhanced enums (Dart 2.17+)

Before, an enum in Dart was just a list of values. Now it can have a constructor, properties and methods, like a normal class — perfect for modeling catalogs of fixed values with behavior (order states, subscription types, etc.).

🧩 2. Extension Methods

Result:

7.esPar
false
7.esPrimo
true

Try a number

extension NumeroUtil on int {
  bool get esPar => this % 2 == 0;

  bool get esPrimo {
    if (this < 2) return false;
    for (int i = 2; i <= this ~/ 2; i++) {
      if (this % i == 0) return false;
    }
    return true;
  }
}

print(7.esPar);   // falseprint(7.esPrimo); // true
💡 ¿Para qué sirven?

The extension add methods/getters to a type that already exists (even int, String or Flutter widgets that you can't modify), without having to inherit from it or wrap it in another class.

📦 3. Records and Patterns (Dart 3)

Result:

persona() (record)
(Marta, 20)
clasificar(persona())
Marta is

Build a record

(String, int) persona() => ('Marta', 20);

// Destructuring: extraer los valores del recordfinal (nombre, edad) = persona();

String clasificar((String, int) p) => switch (p) {
  (_, int e) when e < 13 => 'niño/a',
  (_, int e) when e < 18 => 'adolescente',
  (_, int e) when e < 65 => 'adulto/a',
  _                      => 'jubilado/a',
};

print(clasificar(persona())); // 
💡 Records

A record ((String, int)) lets you return several values from a function without having to create a class just for that. Combined with switch and patterns, you can "destructure" and examine its content in a very compact way.

🎯 Key Concepts

Enhanced enums

  • Constructor, properties, methods
  • Each value is a const instance

Extension methods

  • extension X on Tipo { ... }
  • Adds functions without inheriting

Records & Patterns

  • (Tipo1, Tipo2) groups values
  • switch + patterns to destructure

💪 Practical Exercise

Combine the three features

  1. Add a value tierra(gravedad: 1.0) to the enum Planeta.
  2. Create an extension on String with a getter esPalindromo.
  3. Create a function that returns a record (double x, double y) representing a point, and classify it by quadrant with switch.

Solution 1

enum Planeta {
  tierra(gravedad: 1.0),
  // ...resto de planetas  ;
  const Planeta({required this.gravedad});
  final double gravedad;
}

Solution 2

extension PalindromoUtil on String {
  bool get esPalindromo => this == split('').reversed.join('');
}

Solution 3

String cuadrante((double, double) punto) => switch (punto) {
  (> 0, > 0) => t('Cuadrante I'),
  (< 0, > 0) => t('Cuadrante II'),
  (< 0, < 0) => t('Cuadrante III'),
  (> 0, < 0) => t('Cuadrante IV'),
  _          => t('Sobre un eje'),
};