My class wraps an iterable object and implements iteration as:
[Symbol.iterator]() { return this.range[Symbol.iterator](); }
The compiler does not enforce the implements Iterable<T>
info - why is that?
class SomeWrapper /* implements Iterable<number> */ {
constructor(public readonly range: MyRange) {}
[Symbol.iterator]() { return this.range[Symbol.iterator](); }
}
class MyRange {
constructor(
public readonly begin: number,
public readonly end: number
) {}
[Symbol.iterator]() {
return new MyRangeIterator(this);
}
}
class MyRangeIterator implements Iterator<number>
{
public index: number
public end: number
constructor(range: MyRange)
{
this.index = range.begin;
this.end = range.end
}
public next(): IteratorResult<number, "no_more_values">
{
if (this.index < this.end) {
return { done: false, value: this.index }
}
return { done: true, value: "no_more_values" }
}
}
usage:
const range = new MyRange(5, 14);
const wrapper = new SomeWrapper(range)
for (const x of wrapper) { // I expected an error here: SomeWrapper - Not Iterable
console.log(x)
}
CodePudding user response:
TypeScript doesn't check if your class implements
Iterable
but checks if your class has Symbol.iterator
property.
It will no longer typecheck when you remove this property or make this property not to return an iterator.
Iterators and Generators explains it.
An object is deemed iterable if it has an implementation for the Symbol.iterator property.
TypeScript typechecks in this way in general as it's based on structural subtyping.
For example, this typechecks even though Y
doesn't implements
X
.
interface X {
readonly x: string;
}
class Y {
readonly x: string = 'y';
}
function f(x: X): void {}
f(new Y());