Lección 11 · 11 de 20
Patrones y clases selladas · Dart
Modele los estados de una pantalla con clases sealed en Dart 3 y trátelos con un switch exhaustivo, patrones de objeto, guardas when y if-case.

Una clase `sealed` (sellada) solo puede tener subtipos en su propio archivo. Es abstracta y, a cambio, el compilador conoce la lista completa de sus subtipos: Loading, Loaded y Failed. Es la forma habitual de modelar los estados de una pantalla en Flutter: cargando, con datos o con error.
render usa una expresión `switch` con patrones de objeto: Loaded(:final items) comprueba que el estado es un Loaded y extrae su campo items en una variable. Los patrones pueden afinar más: Loaded(items: []) solo encaja con la lista vacía, Failed(code: 401) con ese código concreto, y la guarda when items.length == 1 añade una condición al caso.
El orden importa: los casos se prueban de arriba abajo y gana el primero que encaja, por eso el general Loaded(:final items) va después de los particulares. Y como la clase está sellada, el switch es exhaustivo: no necesita default, y si se borra el caso Loading() o se añade un estado nuevo, el programa no compila hasta cubrirlo.
Los patrones no son solo para clases. La última línea usa if (json case ...) con un patrón de mapa y otro de lista: comprueba que hay una clave user de tipo String y una lista roles cuyo primer elemento es texto (... acepta el resto), y de paso guarda los valores en name y role. Es una forma segura de leer JSON sin una cadena de comprobaciones y conversiones.
Código · main.dart
// sealed: every subtype is declared in this file, so the compiler// knows the complete list and can check that a switch covers it.sealed class LoadState {}class Loading extends LoadState {}class Loaded extends LoadState { final List<String> items; Loaded(this.items);}class Failed extends LoadState { final int code; final String message; Failed(this.code, this.message);}// Exhaustive switch: no default needed; forget a case and it won't compile.String render(LoadState state) => switch (state) { Loading() => 'Showing spinner...', Loaded(items: []) => 'Nothing here yet', Loaded(:final items) when items.length == 1 => 'One item: ${items[0]}', Loaded(:final items) => '${items.length} items: ${items.join(', ')}', Failed(code: 401) => 'Session expired, please log in', Failed(:final code, :final message) => 'Error $code: $message', };void main() { final states = [Loading(), Loaded([]), Loaded(['Milk']), Loaded(['Tea', 'Rice']), Failed(401, 'Unauthorized'), Failed(503, 'Server busy')]; for (final state in states) print(render(state)); // Patterns also check and unpack a map, such as decoded JSON. final Object json = {'user': 'carmen', 'roles': ['admin', 'editor']}; if (json case {'user': String name, 'roles': [String role, ...]}) print('$name is $role');}Salida · dart run main.dart
Showing spinner... Nothing here yet One item: Milk 2 items: Tea, Rice Session expired, please log in Error 503: Server busy carmen is admin
Para recordar
sealedfija la lista de subtipos en el mismo archivo.- Un
switchsobre una clase sellada es exhaustivo: no hace faltadefault. Clase(:final campo)comprueba el tipo y extrae el campo.whenañade una condición a un caso.if (valor case patrón)valida y desestructura a la vez.
Ejercicio
Añada un estado Offline a la clase sellada, observe el error del compilador en render y añada el caso que escriba No connection.