olivierr91
olivierr91

Reputation: 1415

How to extend IterableIterator in TypeScript

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

Answers (1)

georg
georg

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

Related Questions