Last active
November 20, 2019 20:24
-
-
Save jtmthf/31a4fbdec5c6658f37e6518949fef5e7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| export function all<T>( | |
| iterable: Iterable<T> | |
| ): iterable is Iterable<Exclude<T, Falsy>>; | |
| export function all<T, V extends T>( | |
| iterable: Iterable<T>, | |
| keyFn: TypePredicate<V, T> | |
| ): iterable is Iterable<V>; | |
| export function all<T>( | |
| iterable: Iterable<T>, | |
| keyFn: Predicate<T> | keyof T | |
| ): boolean; | |
| export function all<T>( | |
| iterable: Iterable<T>, | |
| keyFn: Predicate<T> | keyof T = x => !!x | |
| ): boolean { | |
| for (const value of iterable) { | |
| if (!(typeof keyFn === "function" ? keyFn(value) : value[keyFn])) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| export function allFP(): <T>( | |
| iterable: Iterable<T> | |
| ) => iterable is Iterable<Exclude<T, Falsy>>; | |
| export function allFP<T, V extends T>( | |
| keyFn: TypePredicate<V, T> | |
| ): (iterable: Iterable<T>) => iterable is Iterable<V>; | |
| export function allFP<T>( | |
| keyFn: Predicate<T> | keyof T | |
| ): (iterable: Iterable<T>) => boolean; | |
| export function allFP<T>( | |
| keyFn?: Predicate<T> | keyof T | |
| ): (iterable: Iterable<T>) => boolean { | |
| return iterable => all(iterable, keyFn!); | |
| } | |
| export function any<T>( | |
| iterable: Iterable<T>, | |
| keyFn: Predicate<T> | keyof T = x => !!x | |
| ): boolean { | |
| for (const value of iterable) { | |
| if (typeof keyFn === "function" ? keyFn(value) : value[keyFn]) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| export function anyFP<T = any>( | |
| keyFN?: Predicate<T> | keyof T | |
| ): (iterable: Iterable<T>) => boolean { | |
| return iterable => any(iterable, keyFN); | |
| } | |
| export function assertEqual<I, J extends I>( | |
| a: Iterable<I>, | |
| b: Iterable<J> | |
| ): asserts a is Iterable<J>; | |
| export function assertEqual<I extends J, J>( | |
| a: Iterable<I>, | |
| b: Iterable<J> | |
| ): asserts b is Iterable<I>; | |
| export function assertEqual<I, J>(a: Iterable<I>, b: Iterable<J>) { | |
| const aIter = iter(a); | |
| const bIter = iter(b); | |
| for (;;) { | |
| const { value: aValue, done: aDone } = aIter.next(); | |
| const { value: bValue, done: bDone } = bIter.next(); | |
| if (aValue !== bValue || aDone !== bDone) { | |
| throw new Error(); | |
| } | |
| if (aDone && bDone) { | |
| return; | |
| } | |
| } | |
| } | |
| export function contains<T>(iterable: Iterable<T>, needle: T): boolean { | |
| return any(iterable, value => value === needle); | |
| } | |
| export function containsFP<T>(needle: T): (iterable: Iterable<T>) => boolean { | |
| return iterable => contains(iterable, needle); | |
| } | |
| export function* enumerate<T>( | |
| iterable: Iterable<T>, | |
| start = 0 | |
| ): Iterable<[number, T]> { | |
| for (const item of iterable) { | |
| yield [start++, item]; | |
| } | |
| } | |
| export function enumerateFP( | |
| start?: number | |
| ): <T>(iterable: Iterable<T>) => Iterable<[number, T]> { | |
| return iterable => enumerate(iterable, start); | |
| } | |
| export function filter<T, V extends T>( | |
| iterable: Iterable<T>, | |
| predicate: TypePredicate<V, T> | |
| ): Iterable<V>; | |
| export function filter<T>( | |
| iterable: Iterable<T>, | |
| predicate: Predicate<T> | |
| ): Iterable<T>; | |
| export function* filter<T>( | |
| iterable: Iterable<T>, | |
| predicate: Predicate<T> | |
| ): Iterable<T> { | |
| for (const item of iterable) { | |
| if (predicate(item)) { | |
| yield item; | |
| } | |
| } | |
| } | |
| export function filterFP<T, V extends T>( | |
| predicate: TypePredicate<V, T> | |
| ): (iterable: Iterable<T>) => Iterable<V>; | |
| export function filterFP<T>( | |
| predicate: Predicate<T> | |
| ): (iterable: Iterable<T>) => Iterable<T>; | |
| export function filterFP<T>( | |
| predicate: Predicate<T> | |
| ): (iterable: Iterable<T>) => Iterable<T> { | |
| return iterable => filter(iterable, predicate); | |
| } | |
| export function iter<T>(iterable: Iterable<T>): Iterator<T> { | |
| return iterable[Symbol.iterator](); | |
| } | |
| export function* map<T, V>( | |
| iterable: Iterable<T>, | |
| mapper: (value: T) => V | |
| ): Iterable<V> { | |
| for (const item of iterable) { | |
| yield mapper(item); | |
| } | |
| } | |
| export function mapFP<T, V>( | |
| mapper: (value: T) => V | |
| ): (iterable: Iterable<T>) => Iterable<V> { | |
| return iterable => map(iterable, mapper); | |
| } | |
| export function max<T>( | |
| iterable: Iterable<T>, | |
| keyFn: (value: T) => number | |
| ): Maybe<T>; | |
| export function max<T>(iterable: Iterable<number>): Maybe<number>; | |
| export function max<T>( | |
| iterable: Iterable<T>, | |
| keyFn?: (value: T) => number | |
| ): Maybe<T> { | |
| let maxValue: Maybe<T>; | |
| for (const value of iterable) { | |
| if (maxValue === undefined || value > (keyFn ? keyFn(value) : value)) { | |
| maxValue = value; | |
| } | |
| } | |
| return maxValue; | |
| } | |
| export function maxFP<T = any>( | |
| keyFn?: (value: T) => number | |
| ): (iterable: Iterable<T>) => Maybe<T> { | |
| return iterable => max(iterable, keyFn!); | |
| } | |
| export function min<T>( | |
| iterable: Iterable<T>, | |
| keyFn: (value: T) => number | |
| ): Maybe<T>; | |
| export function min<T>(iterable: Iterable<number>): Maybe<number>; | |
| export function min<T>( | |
| iterable: Iterable<T>, | |
| keyFn?: (value: T) => number | |
| ): Maybe<T> { | |
| let minValue: Maybe<T>; | |
| for (const value of iterable) { | |
| if (minValue === undefined || value < (keyFn ? keyFn(value) : value)) { | |
| minValue = value; | |
| } | |
| } | |
| return minValue; | |
| } | |
| export function minFP<T = any>( | |
| keyFn?: (value: T) => number | |
| ): (iterable: Iterable<T>) => Maybe<T> { | |
| return iterable => min(iterable, keyFn!); | |
| } | |
| export function range(stop: number): Iterable<number>; | |
| export function range( | |
| start: number, | |
| stop: number, | |
| step?: number | |
| ): Iterable<number>; | |
| export function* range( | |
| startOrStop: number, | |
| stop?: number, | |
| step = 1 | |
| ): Iterable<number> { | |
| let i = stop === undefined ? 0 : startOrStop; | |
| stop = stop === undefined ? startOrStop : stop; | |
| while (i < stop) { | |
| yield i; | |
| i += step; | |
| } | |
| } | |
| export function reduce<T, O>( | |
| iterable: Iterable<T>, | |
| reducer: (previous: O, next: T) => O, | |
| start: O | |
| ): O; | |
| export function reduce<T>( | |
| iterable: Iterable<T>, | |
| reducer: (previous: T, next: T) => T | |
| ): Maybe<T>; | |
| export function reduce<T, O>( | |
| iterable: Iterable<T>, | |
| reducer: (previous: O, next: T) => O, | |
| start?: O | |
| ): O { | |
| let startSupplied = arguments.length === 3; | |
| let accumulator: any = start; | |
| for (const value of iterable) { | |
| if (!startSupplied) { | |
| accumulator = value; | |
| startSupplied = true; | |
| continue; | |
| } | |
| accumulator = reducer(accumulator, value); | |
| } | |
| return accumulator; | |
| } | |
| export function reduceFP<T>( | |
| reducer: (previous: T, next: T) => T | |
| ): { | |
| (start: T): (iterable: Iterable<T>) => T; | |
| (iterable: Iterable<T>): Maybe<T>; | |
| }; | |
| export function reduceFP<T, O>( | |
| reducer: (previous: O, next: T) => O | |
| ): (start: O) => (iterable: Iterable<T>) => O; | |
| export function reduceFP<T, O>( | |
| reducer: (previous: O, next: T) => O | |
| ): (startOrIterable: O | Iterable<T>) => any { | |
| return startOrIterable => { | |
| return isIterable(startOrIterable) | |
| ? reduce(startOrIterable, reducer as any) | |
| : (iterable: Iterable<T>) => reduce(iterable, reducer, startOrIterable); | |
| }; | |
| } | |
| export function pipe<R>(func: () => R): Pipe<R, typeof func>; | |
| export function pipe<A0, R>(func: (a0: A0) => R): Pipe<R, typeof func>; | |
| export function pipe<A0, A1, R>( | |
| func: (a0: A0, a1: A1) => R | |
| ): Pipe<R, typeof func>; | |
| export function pipe<A0, A1, A2, R>( | |
| func: (a0: A0, a1: A1, a2: A2) => R | |
| ): Pipe<R, typeof func>; | |
| export function pipe<R>(func: (...args: any[]) => R): Pipe<R, typeof func> { | |
| function composed(...args: any[]) { | |
| return func(...args); | |
| } | |
| composed.pipe = <V>(pipedFunc: (value: R) => V) => { | |
| return pipe((...args: any[]) => pipedFunc(func(...args))); | |
| }; | |
| return composed; | |
| } | |
| export function isIterable(value: any): value is Iterable<any> { | |
| return value && value[Symbol.iterator]; | |
| } | |
| export type Falsy = false | 0 | 0n | "" | null | undefined; | |
| export type Predicate<T> = (val: T) => boolean; | |
| export type TypePredicate<T extends V, V = unknown> = (val: V) => val is T; | |
| export type Maybe<T> = T | undefined; | |
| type Pipe<T, F extends (...args: any[]) => any> = { | |
| pipe<V>(func: (value: T) => V): Pipe<V, (...args: Parameters<F>) => V>; | |
| } & F; | |
| const sum = pipe(range) | |
| .pipe(mapFP(x => x * x)) | |
| .pipe(filterFP(x => x % 2 === 0)) | |
| .pipe(reduceFP<number>((sum, next) => sum + next)(0))(1_000_000_000); | |
| console.log(sum); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment