I’m trying to write a function that accepts either Iterable<T> or `AsyncIterable and maps it:
function map<T, U>(
fn: (item: T) => U,
items: Iterable<T> | AsyncIterable<T>,
): Iterable<U> | Iterable<U> & AsyncIterable<U> {
async function* asyncMapper() {
for await (const item of items) {
yield fn(item);
}
}
if (!items[Symbol.iterator]) {
return asyncMapper()
}
return {
*[Symbol.iterator]() {
for (const item of items) {
yield fn(item);
}
},
[Symbol.asyncIterator]: asyncMapper,
};
}
The gist of it is that, if the items implements Symbol.iterator we will return an iterable that can iterate both synchronously and asynchronously. However if we don’t we will return only the async iterable.
The problem is that I cannot typeguard the existence of Symbol.iterator because of the error:
error TS7053: Element implicitly has an
anytype because expression of typesymbolcan't be used to index typeIterable<T> | AsyncIterable<T>.
Does anyone know how to typeguard Symbol.iterator, or if I’m doing something wrong here?
Use a user-defined type guard:
Playground link