Skip to content

Instantly share code, notes, and snippets.

@itsMapleLeaf
Created December 14, 2023 17:15
Show Gist options
  • Save itsMapleLeaf/eeed3cbfe07387e7761d79419406f44c to your computer and use it in GitHub Desktop.
Save itsMapleLeaf/eeed3cbfe07387e7761d79419406f44c to your computer and use it in GitHub Desktop.
extended iterable
import type { Truthy } from "./types.ts"
class ExtendedIterable<T> implements Iterable<T> {
constructor(private iterable: Iterable<T>) {}
*[Symbol.iterator]() {
yield* this.iterable
}
apply<U>(fn: (iterable: ExtendedIterable<T>) => Iterable<U>) {
return new ExtendedIterable(fn(this))
}
map<U>(mapper: (value: T) => U) {
return this.apply(function* (iterable: ExtendedIterable<T>) {
for (const value of iterable) {
yield mapper(value)
}
})
}
filter(filter: BooleanConstructor): ExtendedIterable<Truthy<T>>
filter<U extends T>(filter: (value: T) => value is U): ExtendedIterable<U>
filter(filter: (value: T) => boolean) {
return this.apply(function* (iterable: ExtendedIterable<T>) {
for (const value of iterable) {
if (filter(value)) yield value
}
})
}
reduce<U>(reducer: (accumulator: U, value: T) => U, initialValue: U) {
let result = initialValue
for (const value of this.iterable) {
result = reducer(result, value)
}
return result
}
array() {
return [...this.iterable]
}
unique() {
return this.apply(function* (iterable: ExtendedIterable<T>) {
const seen = new Set<T>()
for (const value of iterable) {
if (!seen.has(value)) {
seen.add(value)
yield value
}
}
})
}
first() {
const iterable = this[Symbol.iterator]().next()
return iterable.done ? undefined : iterable.value
}
}
export type { ExtendedIterable }
/** Helper to wrap an iterator with useful methods */
export function it<T>(iterable: Iterable<T>) {
return new ExtendedIterable(iterable)
}
it.objectEntries = function objectEntries<T>(obj: Record<string, T>) {
return it(Object.entries(obj))
}
it.factory = function factory<Args extends unknown[], Return>(
fn: (...args: Args) => Iterable<Return>,
) {
return (...args: Args) => new ExtendedIterable(fn(...args))
}
it.promise = {
all: <T>(fn: () => Iterable<T | PromiseLike<T>>) => Promise.all(fn()),
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment