How to make Typescript objects iterable? In Python 3 I can do
class EndlessCounter:
def __init__(self):
self.count = 0
def __iter__(self):
return self
def __next__(self):
self.count += 1
return self.count
but what is the Typescript equivalent of this code?
Thanks!
Javascript supports Iterators and generators, typescript doesn't add much to it: typescript Iterators and Generators.
Your code can be done like this in javascript:
function* generator() {
let counter = 0;
while (true) {
yield counter++;
}
}
var iterator = generator();
console.log(iterator.next().value); // 0
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
You can do the same with a class:
class Counter implements Iterator<number> {
private counter = 0;
public next(): IteratorResult<number> {
return {
done: false,
value: this.counter++
}
}
}
let c = new Counter();
console.log(c.next().value); // 0
console.log(c.next().value); // 1
console.log(c.next().value); // 2
The first solution with the generator works well with the for/of loop:
function* generator() {
let counter = 0;
while (counter < 5) {
yield counter++;
}
}
for (let i of generator()) console.log(i);
Prints 0 to 5, however, to do that with an instance you'll need to do:
class Counter implements Iterable<number> {
private counter = 0;
public [Symbol.iterator]() {
return {
next: function() {
return {
done: this.counter === 5,
value: this.counter++
}
}.bind(this)
}
}
}
let c = new Counter();
for (let i of c) console.log(i);
The accepted answer will only work for a single iteration (thus it can also not support nested iterations) and the worst thing is that it will enter an endless loop when you try to iterate again.
here's a version that fixes these issues:
class Counter implements Iterable<number> {
[Symbol.iterator]() {
let counter = 0;
return {
next: () => {
return {
done: counter >= 5,
value: counter++
}
}
}
}
}
count=0
counter
until we are donenow multiple iterations work:
let c = new Counter();
for (let i of c) console.log(i);
for (let i of c) console.log(i);
and nested iterations also works:
let c = new Counter();
for (let i of c) {
console.log('OUTER', i);
for (let i of c) {
console.log('--inner', i);
}
}
Playground example
An alternative is to use a generator function which results in shorter code (see Krisztián Ballas answer):
class Counter implements Iterable<number> {
*[Symbol.iterator](): IterableIterator<number> {
let counter = 0;
while (counter < 5) {
yield counter++;
}
}
}
Playground example
Let's say you have a simple class that wraps a string object:
class StringWrapper {
private readonly wrappedString: string;
public constructor(str: string) {
this.wrappedString = str;
}
*[Symbol.iterator](): IterableIterator<string> {
for (let i = 0; i < this.wrappedString.length; ++i) {
yield this.wrappedString[i];
}
}
}
The iterator is a generator function which yields one character after another from the wrapped string.
Now you can do things like this:
const wstr = new StringWrapper("abcd");
for (const char of wstr) {
console.log(char); // will output "a", "b", "c", "d" separately
}
const anotherString == [..wstr]; // will be "abcd"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With