Métodos de extensión
Aprende cómo añadir funcionalidad a APIs existentes.
Los métodos de extensión añaden funcionalidad a las bibliotecas existentes. Es posible que utilices métodos de extensión sin siquiera saberlo. Por ejemplo, cuando utilizas el autocompletado de código en un IDE, este sugiere métodos de extensión junto con los métodos normales.
Si ver videos te ayuda a aprender, echa un vistazo a esta descripción general de los métodos de extensión.
Descripción general
#Cuando estás utilizando la API de otra persona o cuando implementas una biblioteca que se utiliza ampliamente, a menudo es poco práctico o imposible cambiar la API. Pero es posible que aún quieras añadir alguna funcionalidad.
Por ejemplo, considera el siguiente código que analiza una cadena para convertirla en un entero:
int.parse('42')
Podría ser agradable —más corto y más fácil de usar con herramientas— que
esa funcionalidad estuviera en String en su lugar:
'42'.parseInt()
Para habilitar ese código,
puedes importar una biblioteca que contenga una extensión de la clase String:
import 'string_apis.dart';
void main() {
print('42'.parseInt()); // Use an extension method.
}
Las extensiones pueden definir no solo métodos,
sino también otros miembros como getters, setters y operadores.
Además, las extensiones pueden tener nombres, lo que puede ser útil si surge un conflicto de APIs.
Así es como podrías implementar el método de extensión parseInt(),
utilizando una extensión (llamada NumberParsing) que opera sobre cadenas:
extension NumberParsing on String {
int parseInt() {
return int.parse(this);
}
}
La siguiente sección describe cómo usar métodos de extensión. Después hay secciones sobre cómo implementar métodos de extensión.
Usar métodos de extensión
#Como todo el código de Dart, los métodos de extensión están en bibliotecas. Ya has visto cómo usar un método de extensión: simplemente importa la biblioteca en la que se encuentra y úsalo como un método ordinario:
// Import a library that contains an extension on String.
import 'string_apis.dart';
void main() {
print('42'.padLeft(5)); // Use a String method.
print('42'.parseInt()); // Use an extension method.
}
Eso es todo lo que normalmente necesitas saber para usar métodos de extensión.
Al escribir tu código, es posible que también necesites saber
cómo los métodos de extensión dependen de los tipos estáticos (a diferencia de dynamic) y
cómo resolver conflictos de APIs.
Tipos estáticos y dynamic
#No puedes invocar métodos de extensión en variables de tipo dynamic.
Por ejemplo, el siguiente código genera una excepción en tiempo de ejecución:
dynamic d = '2';
print(d.parseInt()); // Runtime exception: NoSuchMethodError
Los métodos de extensión sí funcionan con la inferencia de tipos de Dart.
El siguiente código es correcto porque
se infiere que la variable v tiene el tipo String:
var v = '2';
print(v.parseInt()); // Output: 2
La razón por la que dynamic no funciona es que
los métodos de extensión se resuelven con respecto al tipo estático del receptor.
Debido a que los métodos de extensión se resuelven de forma estática,
son tan rápidos como llamar a una función estática.
Para obtener más información sobre los tipos estáticos y dynamic, consulta
El sistema de tipos de Dart.
Conflictos de APIs
#Si un miembro de extensión entra en conflicto con una interfaz o con otro miembro de extensión, tienes algunas opciones.
Una opción es cambiar la forma en que importas la extensión en conflicto,
usando show o hide para limitar la API expuesta:
// Defines the String extension method parseInt().
import 'string_apis.dart';
// Also defines parseInt(), but hiding NumberParsing2
// hides that extension method.
import 'string_apis_2.dart' hide NumberParsing2;
void main() {
// Uses the parseInt() defined in 'string_apis.dart'.
print('42'.parseInt());
}
Otra opción es aplicar la extensión explícitamente, lo que da como resultado un código que parece como si la extensión fuera una clase envoltura (wrapper class):
// Both libraries define extensions on String that contain parseInt(),
// and the extensions have different names.
import 'string_apis.dart'; // Contains NumberParsing extension.
import 'string_apis_2.dart'; // Contains NumberParsing2 extension.
void main() {
// print('42'.parseInt()); // Doesn't work.
print(NumberParsing('42').parseInt());
print(NumberParsing2('42').parseInt());
}
Si ambas extensiones tienen el mismo nombre, es posible que debas importarlas usando un prefijo:
// Both libraries define extensions named NumberParsing
// that contain the extension method parseInt(). One NumberParsing
// extension (in 'string_apis_3.dart') also defines parseNum().
import 'string_apis.dart';
import 'string_apis_3.dart' as rad;
void main() {
// print('42'.parseInt()); // Doesn't work.
// Use the ParseNumbers extension from string_apis.dart.
print(NumberParsing('42').parseInt());
// Use the ParseNumbers extension from string_apis_3.dart.
print(rad.NumberParsing('42').parseInt());
// Only string_apis_3.dart has parseNum().
print('42'.parseNum());
}
Como muestra el ejemplo, puedes invocar métodos de extensión implícitamente incluso si los importas usando un prefijo. El único momento en que necesitas usar el prefijo es para evitar un conflicto de nombres al invocar una extensión explícitamente.
Implementar métodos de extensión
#Usa la siguiente sintaxis para crear una extensión:
extension <extension name>? on <type> { // <extension-name> is optional
(<member definition>)* // Can provide one or more <member definition>.
}
Por ejemplo, así es como podrías implementar una extensión en la clase String:
extension NumberParsing on String {
int parseInt() {
return int.parse(this);
}
double parseDouble() {
return double.parse(this);
}
}
Los miembros de una extensión pueden ser métodos, getters, setters u operadores. Las extensiones también pueden tener campos estáticos y métodos de ayuda estáticos. Para acceder a miembros estáticos fuera de la declaración de la extensión, invócalos a través del nombre de la declaración como en variables y métodos de clase.
Extensiones sin nombre
#Al declarar una extensión, puedes omitir el nombre. Las extensiones sin nombre son visibles solo en la biblioteca donde se declaran. Dado que no tienen nombre, no se pueden aplicar explícitamente para resolver conflictos de APIs.
extension on String {
bool get isBlank => trim().isEmpty;
}
Implementar extensiones genéricas
#Las extensiones pueden tener parámetros de tipo genérico.
Por ejemplo, aquí tienes un código que extiende el tipo incorporado List<T>
con un getter, un operador y un método:
extension MyFancyList<T> on List<T> {
int get doubleLength => length * 2;
List<T> operator -() => reversed.toList();
List<List<T>> split(int at) => [sublist(0, at), sublist(at)];
}
El tipo T se vincula en función del tipo estático de la lista sobre la
cual se llaman los métodos.
Recursos
#Para obtener más información sobre los métodos de extensión, consulta lo siguiente:
A menos que se indique lo contrario, la documentación en este sitio refleja Dart 3.12.2. Página actualizada por última vez el 2025-11-04. Ver fuente oreportar un problema.