Dart en 2026: menos boilerplate con primary constructors, dot shorthands y private named parameters
Si escribes Dart a diario, probablemente hayas repetido el nombre de una clase tres veces solo para declarar un constructor, o hayas tecleado Status.running cientos de veces cuando el tipo ya era obvio. Entre Dart 3.10 y Dart 3.13, el lenguaje ha ido cerrando esos huecos con tres funcionalidades concretas: dot shorthands, private named parameters y primary constructors. La respuesta corta: hoy puedes declarar una clase de datos en una sola línea, inicializar campos privados sin listas de inicialización y omitir el tipo cuando el compilador puede inferirlo. La respuesta larga —qué usar, qué no, y qué implica para tu base de código— es lo que cubrimos aquí.
Este artículo va dirigido a equipos que ya tienen Dart/Flutter en producción y quieren decidir con criterio qué adoptar y en qué orden, sin caer en el "azúcar sintáctico porque sí".
El problema: el boilerplate histórico de Dart
Dart siempre ha sido explícito, y eso es una virtud para leer código ajeno. El precio ha sido la verbosidad en tres puntos muy repetitivos:
- Constructores de clases de datos: declarar el campo, y luego repetirlo en el constructor con
this.campo. - Campos privados: los initializing formals (
this.campo) no funcionaban con campos privados en parámetros con nombre, obligando a listas de inicialización manuales. - Referencias a enums y factories: repetir el tipo (
Status.running,int.parse(...)) incluso cuando el contexto ya lo determina.
Las tres funcionalidades que siguen atacan exactamente esos tres puntos. Ninguna cambia la semántica del lenguaje: es el mismo Dart, con menos ruido.
Dot shorthands (Dart 3.10): omite el tipo cuando es inferible
Los dot shorthands permiten empezar una expresión con un punto y dejar que el compilador infiera el tipo a partir del contexto. Requieren una versión de lenguaje mínima de Dart 3.10.
enum Status { none, running, stopped, paused }
// Antes
Status current = Status.running;
// Ahora
Status current = .running;
Funciona con enums, constantes, constructores con nombre y miembros estáticos:
int port = .parse('8080'); // en lugar de int.parse('8080')
Point origin = .origin(); // constructor con nombre
List<int> zeros = .filled(5, 0); // constructor sin nombre
Donde realmente brilla es en llamadas donde el tipo del parámetro ya está declarado —widgets de Flutter, argumentos de funciones, valores por defecto— porque elimina la redundancia sin sacrificar legibilidad.
Cuándo NO usarlo. Hay tres límites que conviene tener presentes:
- El compilador debe poder inferir el tipo del contexto. Si no hay tipo objetivo claro, no compila.
- En comparaciones de igualdad, el shorthand solo puede ir a la derecha:
myColor == .green, no al revés. - Una sentencia no puede empezar por
.. Los dot shorthands son expresiones, no puntos de entrada.
Nuestra recomendación: úsalo donde el tipo destino es evidente a primera vista. Si un revisor tiene que pararse a deducir qué tipo es .parse(...), has perdido más de lo que has ganado.
Private named parameters (Dart 3.12): campos privados sin ceremonia
Dart 3.12 (mayo de 2026) hizo estable que los initializing formals funcionen con campos privados en parámetros con nombre. Antes, un campo privado en un constructor con nombre exigía una lista de inicialización manual. Ahora no:
class Hummingbird {
final String _petName;
final int _wingbeatsPerSecond;
Hummingbird({required this._petName, required this._wingbeatsPerSecond});
}
El constructor expone los nombres públicos (petName, wingbeatsPerSecond) e inicializa directamente los campos privados. Es un cambio pequeño, pero elimina una fricción diaria en cualquier clase con encapsulación real —es decir, en casi todo el código de producción bien escrito.
Primary constructors (Dart 3.13): la clase de datos en una línea
La funcionalidad más esperada. Los primary constructors son estables desde Dart 3.13 y permiten declarar campos y constructor principal en la propia cabecera de la clase. Los parámetros marcados con var o final crean campos de instancia automáticamente.
// Antes
class Point {
final int x;
final int y;
Point(this.x, this.y);
}
// Con primary constructor
class Point(final int x, final int y);
Soportan constructores con nombre, cuerpo de constructor y enums:
// Constructor con nombre
class Point.custom(var int x, var int y);
// Con cuerpo y aserciones
class Point(final int x, final int y) {
this : assert(x >= 0 && y >= 0) {
print('Point en ($x, $y)');
}
}
// Con enums
enum Color(final String hex) {
red('#FF0000'),
green('#00FF00'),
blue('#0000FF');
}
En la misma línea evolutiva, Dart 3.13 también introdujo una sintaxis concisa para constructores adicionales con new y factory dentro del cuerpo, sin repetir el nombre de la clase.
Cuándo NO usarlo. Los primary constructors no son un reemplazo universal:
- Los parámetros no pueden ser
lateniexternal. - No puedes asignar a un parámetro del primary constructor dentro de una lista de inicialización.
- Las colisiones de nombre con métodos o campos existentes son error de compilación.
- Las
mixin classsolo admiten primary constructors triviales (sin parámetros, sin inicializadores, sin cuerpo). - Ojo con un cambio de ruptura asociado: usar
finalovaren parámetros de funciones normales pasó a ser error de compilación al estabilizarse esta sintaxis.
Para clases con lógica de construcción compleja —validaciones ramificadas, múltiples constructores factory, dependencias inyectadas— el constructor tradicional sigue siendo más claro. Los primary constructors ganan en value objects, DTOs, modelos inmutables y clases de datos, que es donde vive la mayor parte del boilerplate.
Tabla comparativa: antes y después
| Caso | Antes | Ahora | Desde |
|---|---|---|---|
| Valor de enum con tipo conocido | Status.running | .running | Dart 3.10 |
| Constructor con nombre inferible | Point.origin() | .origin() | Dart 3.10 |
| Campo privado en named param | Lista de inicialización manual | this._campo | Dart 3.12 |
| Clase de datos inmutable | Campo + this.campo en constructor | class Point(final int x, final int y); | Dart 3.13 |
Qué significa para tu equipo
Estas tres funcionalidades no justifican por sí solas una migración masiva, pero sí una decisión consciente:
- Alinea la versión de lenguaje. Los dot shorthands piden 3.10; los primary constructors, 3.13. Sube el
sdkmínimo enpubspec.yamlde forma deliberada, no por inercia, y comprueba el impacto en dependencias y CI. - Adopta por capas, no de golpe. Empieza por los value objects y DTOs nuevos con primary constructors. No reescribas constructores complejos que ya funcionan solo por estética: el diff sin valor de negocio es deuda de revisión.
- Cuidado con el cambio de ruptura. El error nuevo sobre
final/varen parámetros de funciones puede aparecer al actualizar. Es trivial de arreglar, pero conviene saberlo antes de que lo descubra el pipeline. - Fija una convención de dot shorthands en tu guía de estilo. La legibilidad depende de que el equipo use el mismo criterio sobre cuándo el tipo destino es "obvio".
El patrón de fondo es coherente: Dart está recortando ceremonia sin tocar su modelo de tipos ni su previsibilidad. Para quien mantiene apps Flutter a largo plazo, eso se traduce en menos líneas que revisar y menos superficie donde equivocarse —sin sorpresas semánticas.
Conclusión
Entre 3.10 y 3.13, Dart ha reducido su boilerplate más molesto con tres herramientas complementarias: dot shorthands para omitir tipos inferibles, private named parameters para inicializar campos privados sin ceremonia, y primary constructors para declarar clases de datos en una línea. Ninguna es azúcar gratuito: cada una tiene un "cuándo no" claro. Adoptadas con criterio, hacen el código más corto y más fácil de leer; adoptadas por moda, solo generan ruido en las revisiones.
En Dribba llevamos desde 2011 construyendo apps con Flutter y Dart, y somos Partner oficial de Google en Flutter desde 2017. Si tu equipo está valorando cómo modernizar una base de código Dart o subir la versión de lenguaje sin romper producción, podemos ayudarte a hacerlo por capas y sin sobresaltos —desde staff augmentation con perfiles senior hasta una revisión de arquitectura. Puedes ver cómo trabajamos en nuestro blog técnico o en artículos como Dart Cloud Functions para Firebase: cuándo usarlo vs Go.




