Exploring various methods to overcome an obstacle in my writing, I discovered a unique solution:
To address this issue, consider implementing a typed iterator with the sync
flag included, as outlined below:
interface TypedIterator<T, TReturn = any, TNext = undefined> {
next(...args: [] | [TNext]): IteratorResult<T, TReturn> | Promise<IteratorResult<T, TReturn>>;
return?(value?: TReturn | PromiseLike<TReturn>): IteratorResult<T, TReturn> | Promise<IteratorResult<T, TReturn>>;
throw?(e?: any): IteratorResult<T, TReturn> | Promise<IteratorResult<T, TReturn>>;
sync: boolean;
}
Furthermore, a conversion utility can be provided for seamless integration:
function toTypedIterator<T>(i: Iterator<T> | AsyncIterator<T>): TypedIterator<T> {
let started = false;
const v = i.next() as any;
const sync = !v || typeof v.then !== 'function';
return {
...i,
sync,
next() {
if (started) {
return i.next();
}
started = true;
return v;
}
};
}
To put this solution to the test, consider using the following example:
const data = [1, 2, 3, 4, 5];
const i = toTypedIterator(data[Symbol.iterator]());
console.log('sync:', i.sync);
do {
const a = i.next();
if (a.done) {
break;
}
console.log(a);
} while (true);
The resulting output showcases the success of this approach:
sync: true
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: 4, done: false }
{ value: 5, done: false }