Skip to content

Instantly share code, notes, and snippets.

@typoerr
Last active April 4, 2017 05:01
Show Gist options
  • Save typoerr/ef6ad7ae6685e5863513e81bc630a924 to your computer and use it in GitHub Desktop.
Save typoerr/ef6ad7ae6685e5863513e81bc630a924 to your computer and use it in GitHub Desktop.
immutable entries collection helpers
export type Entries<K, V> = Entry<K, V>[];
export type Entry<K, V> = [K, V];
export type Iteratee<K, V, R> = (v: V, k: K, index: number, src: Entries<K, V>) => R;
namespace util {
export function existy(v: any) {
return !(v === null || v === undefined);
}
export function includes<T>(src: T[], target: T) {
return src.indexOf(target) >= 0;
}
export function makeIteratee<K, V, R>(fn: Iteratee<K, V, R>, context: object | undefined) {
return function (e: Entry<K, V>, i: number, co: Entries<K, V>): R {
return fn.call(context, e[1], e[0], i, co);
};
}
}
export function has<K, V>(co: Entries<K, V>, key: K) {
return util.existy(get(co, key));
}
export function get<K, V>(co: Entries<K, V>, key: K) {
const results = co.find(([k]) => k === key);
return util.existy(results) ? results : undefined;
}
export function set<K, V>(co: Entries<K, V>, key: K, value: V) {
return merge(co, [[key, value]]);
}
export function merge<K, V>(co: Entries<K, V>, src: Entries<K, V>) {
const map = new Map(co);
src.forEach(([k, v]) => map.set(k, v));
return Array.from(map);
}
export function pick<K, V>(co: Entries<K, V>, keys: K[]) {
return filter(co, (_, k) => util.includes(keys, k));
}
export function remove<K, V>(co: Entries<K, V>, key: K) {
return filter(co, (_, k) => k !== key);
}
export function keys<K, V>(co: Entries<K, V>) {
return co.map(([k]) => k);
}
export function values<K, V>(co: Entries<K, V>) {
return co.map(([_, v]) => v);
}
export function first<K, V>(co: Entries<K, V>): Entry<K, V> | undefined {
return co.length > 0 ? [...co][0] : undefined;
}
export function last<K, V>(co: Entries<K, V>): Entry<K, V> | undefined {
return [...co].reverse()[0];
}
export function forEach<K, V>(co: Entries<K, V>, callback: Iteratee<K, V, void>, context?: object) {
return co.forEach(util.makeIteratee(callback, context));
}
export function filter<K, V>(co: Entries<K, V>, callback: Iteratee<K, V, boolean>, context?: object) {
return co.filter(util.makeIteratee(callback, context));
}
export function map<K, V, R>(co: Entries<K, V>, callback: Iteratee<K, V, R>, context?: object): R[] {
return co.map(util.makeIteratee(callback, context));
}
export function reduce<K, V, T>(co: Entries<K, V>, callback: _reduce.callback<K, V, T>, init: T): T {
return co.reduce(_reduce.makeReducer(callback), init);
}
export namespace _reduce {
export type callback<K, V, T> = (acc: T, value: V, key: K, index: number, src: Entries<K, V>) => T;
export function makeReducer<K, V, T>(callback: _reduce.callback<K, V, T>) {
return function (acc: T, kv: Entry<K, V>, i: number, src: Entries<K, V>) {
return callback.call(null, acc, kv[1], kv[0], i, src);
};
}
}
export function toEntries<T, K extends keyof T, V extends T[K]>(src: T): Entries<string, V> {
return Object.keys(src).map((k: K) => [k, src[k]]) as Entries<K, V>;
}
export function toHash<K, V>(co: Entries<K, V>) {
return co.reduce((acc, [k, v]) => {
acc[k + ""] = v;
return acc;
}, {} as { [k: string]: V });
}
export function toMap<K, V>(col: Entries<K, V>) {
return new Map(col);
}
export function fromMap<K, V>(map: Map<K, V>) {
return Array.from(map);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment