export interface GenericFunction { (a: A): B } export interface Hash { [key: string]: A }; export interface ObjectReducer { (accum?: B, value?: A, key?: string, hash?: Hash): B } export interface ObjectMapper { (value?: A, key?: string, hash?: Hash): B } /** * identity is the famed identity function. */ export const identity = (a: A): A => a; export interface O { [key: string]: A } /** * merge two objects easily */ export const merge = (...o: A[]): B => Object.assign.apply(Object, [{}].concat(o)); /** * fuse is the deep version of merge */ export const fuse = (...args: A[]): B => args.reduce((o: B, c: A = ({})) => reduce(c, (co: B, cc: any, k: string) => Array.isArray(cc) ? (Array.isArray((co)[k]) ? merge(co, { [k]: ((co)[k]).map(copy).concat(cc.map(copy)) }) : merge(co, { [k]: cc.map(copy) })) : typeof cc !== 'object' ? merge(co, { [k]: cc }) : merge(co, { [k]: (typeof (co)[k] !== 'object') ? merge((co)[k], cc) : fuse((co)[k], cc) }), o), {}) export const copy = (o: A): B => (Array.isArray(o)) ? o.map(copy) : (typeof o === 'object') ? reduce(o, (p, c, k) => merge(p, { [k]: copy(c) }), {}) : o; /** * reduce an object's keys (in no guaranteed order) */ export const reduce = (o: Hash, f: ObjectReducer, accum?: B) => Object.keys(o).reduce((p, k) => f(p, o[k], k, o), accum); /** * map over an object (in no guaranteed oreder) */ export const map = (o: Hash, f: ObjectMapper) => Object.keys(o).map((k => f(o[k], k, o))); /** * compose two functions into one. */ export const compose = (f: (a: B) => C, g: (a: A) => B) => (x: A) => f(g(x)); /** * fling removes a key from an object * @param {string} key * @param {object} object * @return {Object} * @summary {(string,Object) → Object} */ export const fling = (s: string, o: Hash) => { if ((o == null) || (o.constructor !== Object)) throw new TypeError('fling(): only works with object literals!'); return Object.keys(o).reduce((o2, k) => k === s ? o2 : merge(o2, { [k]: o[k] }), {}); } /** * head returns the item at index 0 of an array * @param {Array} list * @return {*} * @summary { Array → * } */ export const head = (list: A[]) => list[0]; /** * tail returns the last item in an array * @param {Array} list * @return {*} * @summary {Array → *} */ export const tail = (list: A[]) => list[list.length - 1]; /** * constant given a value, return a function that always returns this value. * @summary constant X → * → X * */ export const constant = (a: A): ((_: any) => A) => () => a; /** * except copies an object removing a single key. */ export const except = , V>(keys: string[], o: O): O => reduce(o, (p, c, k) => keys.indexOf(k) > -1 ? p : merge(p, { [k]: c }), {});