Skip to main content

Iterator pattern en TypeScript

⏱ Dedicación recomendada: 0 minutos
Esto considera el contenido visible y relevante, e ignora texto colapsado o marcado como opcional.


r8vnhill/

El patrón Iterador es una técnica utilizada en programación orientada a objetos para recorrer una colección de manera secuencial sin exponer su estructura interna. En TypeScript, este patrón se implementa utilizando la interfaz iterable nativa y los generadores (generators), ofreciendo un enfoque flexible para recorrer estructuras de datos.

📌 Iteradores en TypeScript

TypeScript proporciona soporte nativo para el patrón iterador a través de la interfaz Iterable<T>, que define el método Symbol.iterator(). Este método retorna un iterador que implementa Iterator<T>, con las funciones next() para avanzar y done para verificar si se ha completado el recorrido.

interface Iterator<T> {
next(): { value: T; done: boolean };
}

interface Iterable<T> {
[Symbol.iterator](): Iterator<T>;
}

🛠️ Implementación del patrón Iterador

Supongamos que queremos modelar una biblioteca que almacena libros y proporciona un iterador para recorrerlos.

🏗️ 1. Definir el Iterador

El primer paso es definir la clase que implementa la interfaz Iterator<T> para recorrer la colección de libros.

class BookIterator implements Iterator<string> {
private position = 0;

constructor(private books: string[]) {}

next(): { value: string; done: boolean } {
if (this.position >= this.books.length) {
return { value: "", done: true };
}
return { value: this.books[this.position++], done: false };
}
}

Aquí, next() devuelve el siguiente libro en la colección hasta que no quedan más elementos.

📚 2. Implementar la colección iterable

La biblioteca debe implementar Iterable<T> para devolver una instancia del iterador.

class Library implements Iterable<string> {
constructor(private books: string[]) {}

[Symbol.iterator](): Iterator<string> {
return new BookIterator(this.books);
}
}

🔄 3. Uso del iterador

Ahora podemos recorrer la biblioteca utilizando un for...of.

const library = new Library([
"Historia del Feminismo",
"El general en su laberinto",
"Choque de reyes"
]);

for (const book of library) {
console.log(book);
}

⚡ Iterador con Generadores en TypeScript

Podemos simplificar el código usando un generador, eliminando la necesidad de una clase iteradora separada:

class Library implements Iterable<string> {
constructor(private books: string[]) {}

*[Symbol.iterator](): IterableIterator<string> {
for (const book of this.books) {
yield book;
}
}
}

📊 Resumen comparativo

AspectoTypeScriptKotlin
Soporte nativoUsa Iterable<T> e Iterator<T> con Symbol.iteratorUsa Iterable<T> e Iterator<T>
Definición del iteradorImplementa Iterator<T> con next() y doneImplementa Iterator<T> con next() y hasNext()
Iteración nativafor...of y el operador de propagación ...for loop y iterator() implícito
Iteradores avanzadosUsa generadores con function*Usa secuencias (Sequence<T>)
Acceso a iteradoreslibrary[Symbol.iterator]()library.iterator()
Control de finalizacióndone: boolean en next() indica fin del recorridohasNext() indica si hay más elementos
Laziness (Evaluación diferida)Disponible con yield en generadoresDisponible con Sequence<T>
ParalelismoNo soporta paralelismo en iteradores nativosPuede usar asIterable() con parallelStream()
Compatibilidad con estructuras existentesFunciona con Array, Set, Map y StringFunciona con List, Set, Map y String
Sobrecarga de memoriaBaja con generadores (yield)Baja con Sequence<T>

✅ Beneficios y ❌ limitaciones de TypeScript

Beneficios

  • Soporte nativo: TypeScript integra Iterable<T> y Symbol.iterator, lo que facilita la implementación del patrón sin necesidad de clases adicionales.
  • Iteración simplificada: Permite recorrer estructuras de datos usando for...of y el operador de propagación ..., evitando el manejo manual del iterador.
  • Evaluación diferida con generadores: Los generadores (function*) permiten recorrer colecciones grandes sin cargar todos los elementos en memoria.
  • Compatibilidad con estructuras nativas: Funciona con Array, Set, Map y String sin necesidad de modificaciones.
  • Interoperabilidad con JavaScript: TypeScript puede trabajar con cualquier iterador de JavaScript, permitiendo su uso en bibliotecas externas y APIs nativas.

Limitaciones

  • Sin control sobre concurrencia: A diferencia de Kotlin, TypeScript no ofrece una alternativa directa para recorrer colecciones en paralelo.
  • Sin soporte para secuencias avanzadas: No tiene un equivalente directo a Sequence<T> de Kotlin, lo que limita la composición funcional de iteradores.
  • Menor seguridad de tipos en iteradores externos: TypeScript permite el uso de iteradores sin verificación estricta, lo que puede generar errores en tiempo de ejecución si los datos no son consistentes.

🎯 Conclusiones

El patrón Iterator en TypeScript ofrece una manera flexible y estructurada de recorrer colecciones sin exponer su implementación interna. Gracias a Iterable<T> y Symbol.iterator, la integración con las estructuras nativas del lenguaje es sencilla, permitiendo iteraciones eficientes y concisas.

A lo largo de la lección, hemos explorado su implementación, su comparación con Kotlin y sus ventajas en términos de simplicidad, evaluación diferida con generadores y compatibilidad con estructuras de datos estándar. También hemos analizado sus limitaciones, como la falta de soporte nativo para concurrencia y secuencias avanzadas.

🔑 Puntos clave

  • Iteración nativa: TypeScript proporciona iteradores de forma integrada con for...of y Symbol.iterator, lo que simplifica su uso.
  • Soporte para evaluación diferida: Los generadores (function*) permiten recorrer colecciones sin cargar todos los elementos en memoria, mejorando la eficiencia.
  • Compatibilidad con estructuras estándar: Funciona de manera directa con Array, Set, Map y String sin necesidad de modificaciones.
  • Diferencias con Kotlin: Aunque ambos lenguajes soportan iteradores, Kotlin ofrece secuencias (Sequence<T>) como alternativa más poderosa para manipulación de datos.

🧰 ¿Qué nos llevamos?

El patrón iterador sigue siendo una herramienta fundamental para la manipulación de colecciones, tanto en TypeScript como en otros lenguajes. En TypeScript, su implementación es natural gracias a Symbol.iterator, y su combinación con generadores lo hace aún más poderoso. Sin embargo, su uso debe evaluarse según el contexto: en colecciones simples, una iteración directa puede ser suficiente, mientras que en estructuras más complejas o grandes volúmenes de datos, los generadores ofrecen una alternativa eficiente.

Si bien existen diferencias con Kotlin en términos de abstracción y soporte para secuencias, ambos enfoques buscan lo mismo: recorrer estructuras de datos de forma eficiente sin comprometer la encapsulación ni la claridad del código. Comprender cómo cada lenguaje implementa este patrón nos permite aprovechar mejor sus capacidades y elegir la mejor solución según nuestras necesidades.

📖 Referencias

🔥 Recomendadas

🌐 Documentation—Iterators and Generators. (s. f.). Recuperado 21 de marzo de 2025, de https://www.typescriptlang.org/docs/handbook/iterators-and-generators.html