¿Cómo implementar Symbol.iterator?

Intento crear una subclass de Conjunto, y como no puedo simplemente extenderme de ella, estoy completando su funcionalidad.

Estoy intentando implementar el método Symbol.iterator, pero Flow no tiene nada de eso.

Este es el código que tengo:

/* @flow */ class CSet<T> { _set: Set<T>; [Symbol.iterator](): Iterator<T> { return this._set[Symbol.iterator]; } } var a: CSet = new CSet(); for(var b of a){ } core.js:309:5,29: property @@iterator Property not found in test.js:2:7,10: CSet test.js:4:2,6:2: computed property keys not supported 

El segundo error no es tan importante, ya que puedo suprimirlo fácilmente. Sin embargo, me pregunto si estoy haciendo algo mal todos juntos.

Debido a que Flow no tiene actualmente soporte general para los símbolos, la forma en que representa Symbol.iterator es hacky y básicamente impide la capacidad de definir iteradores en el espacio de usuario por ahora (su soporte solo funciona en las definiciones de la biblioteca) 🙁

Específicamente Flow espera que un iterable tenga una propiedad @@iterator en ellos (que ciertamente no es un nombre de propiedad válido, pero esto fue un truco temporal para get soporte en las definiciones de la biblioteca).

Por lo tanto, hasta que aterrice el símbolo apropiado, la mejor opción para una solución alternativa sería crear una definición de biblioteca para este module que use esta propiedad @@iterator para la comprensión de Flow:

 // RealModule.js export class CSet { [Symbol.iterator]() { return this._set[Symbol.iterator]; } } 

.

 // RealModule.FlowLibDef.js declare module RealModule { declare class CSet<T> { _set: Set<T>; @@iterator(): Iterator<T>; } } 
 // @flow class MyCollection<T> { /*:: @@iterator(): Iterator<T> { return ({}: any); } */ // $FlowFixMe: computed property [Symbol.iterator](): Iterator<T> { // NOTE: this could just as easily return a different implementation return new MyIterator(this); } } class MyIterator<+T> { /*:: @@iterator(): Iterator<T> { return (this: any); } */ // $FlowFixMe: computed property [Symbol.iterator](): Iterator<T> { return this; } next(): IteratorResult<T, void> { return { done: false, value: someT }; // or return { done: true, value: undefined }; } } for (const value of new MyCollection()) { console.log(value); } 

El motivo por el que esto funciona es que flow interpreta /*:: code */ como si fuera código de flujo en la fuente, excepto que está comentada en time de ejecución, por lo tanto, no afecta realmente el código.

Flow conoce intrínsecamente el método @@iterator , a pesar de no ser JavaScript válido, por lo tanto, lo definimos como existente, devolviendo un Iterator<T> y devolviendo un valor que funciona para él (es decir, un object vacío como any ).

El método de propiedad computada es entonces ignorado completamente por el flujo, como si no estuviera definido en absoluto. Es crucial que realmente devuelva un Iterator<T> válido Iterator<T> del método, de lo contrario las cosas se romperán en el time de ejecución.

Encontré un truco que te permite marcar una class definida por el usuario como iterable, sin necesidad de escribir y mantener un libdef paralelo para toda tu class.

La key es escribir una superclass dedicada que implemente [Symbol.iterator]() y proporcione un libdef solo para esa superclass:

 // IterableBase.js export default class IterableBase { [Symbol.iterator]() { return this._Symbol_iterator(); } } 
 // IterableBase.js.flow // @flow declare class IterableBase<T> { @@iterator(): Iterator<T>; } export default IterableBase; 

Ahora puede hacer que su class personalizada amplíe IterableBase e implemente el nombre del método sustituto:

 // RealModule.js // @flow import IterableBase from './IterableBase'; class CSet<T> extends IterableBase<T> { _Symbol_iterator(): Iterator<T> { ... } } 

Esto obviamente sigue siendo un truco, pero debería ser más fácil y más seguro que la alternativa.

testing este código javascript

 // module -- start let map = new WeakMap(); class Foo { constructor(any) { map.set(this, new Set(any)); } values() { return map.get(this).values(); } [Symbol.iterator]() { return this.values(); } } // module -- end for(let item of new Foo([1,2,3])) { console.log(item); } 

ver

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
  2. salvadera