import { Moment } from "moment"; type Simplify = string | T extends string ? string : T extends number ? number : T extends boolean ? boolean : T extends Moment ? string : T extends Array ? Array> : T extends (infer K)[] ? Simplify[] : T extends Object ? Jsonified : any; export type Jsonified = { [K in keyof T]: Simplify } export type Optionalify = { [K in keyof T]?: T[K] } export type Dictionary = { [key: string]: T }; export type Index = string | symbol | number; export type FetchingState = 'fetching' | 'ready' | 'error' | 'not-initialized'; export function map(source: T, mapper: (value: T[KT], key: KT) => R[KT]): R { const result: R = {} as R; for (const [key, value] of Object.entries(source)) { result[key] = mapper(value as T[KT], key as KT); } return result; } export function filter(source: T, filter: (value: T[KT], key: KT) => boolean): Optionalify { const result: Optionalify = {}; for (const [key, value] of Object.entries(source)) { if (filter(value as T[KT], key as KT)) { result[key] = value; } } return result; } export function signed(number: number): string { return number > 0 ? `+${number}` : number.toString(); } export function ensureArray(x: T[]|T): T[] { return x instanceof Array ? x : [ x ]; } export function set(object: any, path: string, value: any) { const segments = path.split('.'); while (segments.length > 1) { object = object[segments.shift()]; } object[segments.shift()] = value; } export function get(object: any, path: string): any { const segments = path.split('.'); while (segments.length > 1) { object = object[segments.shift()]; } return object[segments.shift()]; } export function distinct(value: T, index: number, array: T[]) { return array.indexOf(value) === index; } export function time(action: () => T, name?: string) { const start = performance.now(); const result = action(); console.debug(`${name || 'this'} operation took ${performance.now() - start}ms`); return result; } export const identity = a => a; export function unique(array: T[], criterion: (item: T) => U = identity) { const result: T[] = []; const known = new Set(); const entries = array.map(item => [ criterion(item), item ]) as [ U, T ][]; for (const [ key, item ] of entries) { if (known.has(key)) { continue; } known.add(key); result.push(item); } return result; } type Pattern = [ (...args: TArgs) => boolean, ((...args: TArgs) => TResult) | TResult, ] export function match(...patterns: Pattern[]): (...args: TArgs) => TResult { return (...args: TArgs) => { for (let [pattern, action] of patterns) { if (pattern(...args)) { return typeof action === "function" ? (action as (...args: TArgs) => TResult)(...args) : action; } } throw new Error(`No pattern matches args: ${JSON.stringify(args)}`); } } match.default = (...args: any[]) => true;