Reputation: 1415
I am trying to extend Iterable
with a where method, similar to C# Enumerable.where()
. Extending the Array
prototype is easy, however I am struggling to find how to extend an Iterable
.
Here is the declaration:
declare interface Iterable<T> {
where<T>(this: Iterable<T>, predicate: (item: T) => boolean): Generator<T>;
}
Problem is with the implementation. The extended method compiles just fine, but at runtime when trying to use that method on an Array
(which is an Iterable
) or any Iterable
, it will throw that where()
isn't defined. On Array
you would just add the method implementation to Array.prototype
, but Iterable
has no prototype:
function* where<T>(this: Iterable<T>, predicate: (item: T) => boolean): Generator<T> {
for (const item of this) {
if (predicate(item)) {
yield item;
}
}
}
Iterable.prototype = function* where(...)
does not work because Iterable
has no prototype.
Here is the desired usage:
public myMethod(myIterable: Iterable<number> ) {
console.log(myIterable.where(i => i > 3));
}
How do I extend Iterable
? Should I be extending IterableIterator
instead?
Someone has managed to do it another thread (https://stackoverflow.com/questions/62008192/typescript-`extending`-iterableiterator-for-array-type-but-return-a-simple-type) but he doesn't show how he extends Iterable and told me to ask another question.
Upvotes: 1
Views: 1336
Reputation: 214949
You can extend the IteratorPrototype
in which case your method will work with built-in Iterators like array.keys()
or star functions, but not Iterables like arrays.
As you correctly said, there's no way to extend Iterable
because no such thing exists at run time. Generally speaking, a more common practice is to design your own "monad" instead of extending built-in prototypes:
result = Enumerable(someIterable)
.where(...)
.map(...)
.etc(...)
.toList()
Upvotes: 2