Chris
Chris

Reputation: 2168

JS/TS Filter On AsyncIterable<T>

I have a variable of type AsyncIterable. I want to filter on it, for example (psuedo code below) -

class SomeClass {
    private SOME_CONST= "ABCDE";

    private async someFunction(): Promise<string> {
        const items: AsyncIterable<string> = await someLibrary.getAsyncItems(); // this library's function returns type of AsyncIterable<T>

        return items.filter(item => item === this.SOME_CONST);
    }
}

How can I filter on AsyncIterable? I get the error - "Property 'filter' does not exist on type 'AsyncIterable'

Upvotes: 0

Views: 631

Answers (3)

TomW
TomW

Reputation: 4002

Spelling out the direct approach:

export async function* filterAsyncIterable<T>(
    iterable: AsyncIterable<T>,
    predicate: (t: T) => boolean,
): AsyncIterable<T> {
    for await (const item of iterable) {
        if (predicate(item)) yield item;
    }
}

Similarly, you can write mapAsyncIterable, etc. and you will also probably need other helpers like asyncIterableToArray and asyncIterableFirst (to get the first element).

Then, your code becomes:

class SomeClass {
    private SOME_CONST= "ABCDE";

    private async someFunction(): AsyncIterable<string> {
        return filterAsyncIterable(
            someLibrary.getAsyncItems(), 
            item => item === this.SOME_CONST,
        );
    }
}

or possibly:

class SomeClass {
    private SOME_CONST= "ABCDE";

    private async someFunction(): Promise<string[]> {
        return asyncIterableToArray(filterAsyncIterable(
            someLibrary.getAsyncItems(), 
            item => item === this.SOME_CONST,
        ));
    }
}

Upvotes: 1

jeeeyul
jeeeyul

Reputation: 3787

Just create another AsyncIterator that wraps original one using generator function.

I made a example for TypeScript:

export function filterAsyncIterator<T>(origin: AsyncIterableIterator<T>, predicate: (element: T) => boolean): AsyncIterableIterator<T> {
    return (async function* () {
        for await (const each of origin) {
            if(predicate(each)){
                yield each;
            }
        }
    })();
}

AsyncIterator is not an actual type. It is an interface that objects can comply by owning a function with named as [Symbol.asyncIterator].

Upvotes: 0

Matthieu Riegler
Matthieu Riegler

Reputation: 54708

You can't filter on a synchronous iterator either, you'll need to it convert it to an array.

At the moment there is no method like Array.from() for AsyncIterable (pending proposal) but you can do following :

async function toArray<T>(asyncIterator: AsyncIterable<T>) {
  const arr = [];
  for await (const i of asyncIterator) arr.push(i);
  return arr;
}

then you can do

declare const items: AsyncIterable<string>;

async function foo() {
  (await toArray(items)).filter(() => true)
}

Playground

Upvotes: 1

Related Questions