Skip to content

Instantly share code, notes, and snippets.

@kennethkeim
Last active December 2, 2022 22:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kennethkeim/3f22e509e897963c8a325ef083c0eb20 to your computer and use it in GitHub Desktop.
Save kennethkeim/3f22e509e897963c8a325ef083c0eb20 to your computer and use it in GitHub Desktop.
Credits to Michael Lowenstein
export const defaultTo = (a: any, b: any): any =>
a == null || Object.is(a, NaN) ? b : a;
export const remove = (data: any[], loopFunc: any): any[] => {
return data.filter(() => {
return !loopFunc.apply(this);
});
};
export const omitThis = (key: string, { [key]: _, ...obj }) => obj;
export const round = (val: number, precision: number): number => {
const decimalFactor = Math.pow(10, precision);
return Math.round(val * decimalFactor) / decimalFactor;
};
export const slice = (inputs: any[], from: number, to?: number): any[] => {
return to ? inputs.slice(from, to) : inputs.slice(from);
};
export const isEqual = (base: any, match: any): boolean => {
const baseType = typeof base;
const matchType = typeof match;
if (baseType != matchType) {
return false;
}
if (baseType == "string" || baseType == "number" || baseType == "boolean") {
return base === match ? true : false;
}
return Object.entries(base).toString() === Object.entries(match).toString();
};
export const clone = (input: any): any => {
if (Array.isArray(input)) {
const output: any[] = [];
input.forEach((ip) => {
output.push(clone(ip));
});
return output;
} else {
return { ...input };
}
};
export const cloneDeep = (inputs: any): any => {
if (Array.isArray(inputs)) {
const output: any[] = [];
inputs.forEach((ip) => {
output.push(cloneDeep(ip));
});
return output;
} else {
return JSON.parse(JSON.stringify(inputs));
}
};
export const union = (...data: any[]): any => {
return data.reduce((first, next) => Array.from([...first, ...next]));
};
export const unionBy = (iteratee: any, ...inputs: any[]) => {
let united: any[] = [];
for (const ip of inputs) {
const mapped = ip.map(iteratee);
const unionMapped = united.map(iteratee);
const uniques = mapped.filter((i: any) => !unionMapped.includes(i));
united = [...united, ...uniques];
}
return united;
};
export const unionWith = (comparator: any, ...inputs: any[]) => {
let united: any[] = [];
for (const ip of inputs) {
const uniques = ip.filter(
(i: any) => !united.find((u) => comparator(i, u)),
);
united = [...united, ...uniques];
}
return united;
};
export const integrate = (oldData: any[], newData: any[]) => {
if (Array.isArray(oldData)) {
return oldData.concat(newData);
}
return newData;
};
/* eslint-disable prefer-const */
/** General Utility Functions: */
export const groupBy = function (array: any[], key: string): any[] {
return array.reduce(function (obj, x) {
(obj[x[key]] = obj[x[key]] || []).push(x);
return obj;
}, {});
};
export const unique = function (array: any[]): any[] {
let vals = "";
let keys: string[];
let newarray: any[];
let unique: any;
unique = {};
newarray = [];
array.forEach((item) => {
vals = "";
keys = item ? Object.keys(item) : [];
keys.forEach((key) => {
vals += item[key] + " ";
});
if (!unique[vals]) {
newarray.push(item);
}
unique[vals] = item;
});
return newarray;
};
export const uniqBy = (data: any[], predicate: any): any => {
const cb =
typeof predicate === "function"
? predicate
: (o: { [x: string]: any }) => o[predicate];
return [
...data
.reduce((map, item) => {
const key = item === null || item === undefined ? item : cb(item);
map.has(key) || map.set(key, item);
return map;
}, new Map())
.values(),
];
};
export const getSorted = function (prop: string) {
return function (a: any, b: any) {
if (a[prop] > b[prop]) {
return 1;
}
if (a[prop] < b[prop]) {
return -1;
}
return 0;
};
};
/** Creates a random 4-char chunk which will be
* concatenated with other chunks to make our
* randomly-generated GUID for batch-posts. */
export const segment = function (): string {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
};
/** Creates a random 32-character GUID for
* string-identifiers values if needed. */
export const generate = function (): string {
return (
segment() +
segment() +
segment() +
"4" +
segment().substr(0, 3) +
segment() +
segment() +
segment() +
segment()
).toLowerCase();
};
export const isEmpty = (value: any): boolean => {
return (
value == null ||
(typeof value === "object" && Object.keys(value).length === 0) ||
(typeof value === "string" && value.trim().length === 0)
);
};
export const orderBy = (
data: any[],
keys: string[] | number[] | string,
): any => {
const sortKeys = Array.isArray(keys) ? keys : [keys];
return data.map((first: any, next: any) => {
return sortKeys.forEach((sortKey: any) => {
return first[sortKey] > next[sortKey]
? 1
: next[sortKey] > first[sortKey]
? -1
: 0;
});
});
};
type GetIndexedField<T, K> = K extends keyof T
? T[K]
: K extends `${number}`
? "0" extends keyof T
? undefined
: number extends keyof T
? T[number]
: undefined
: undefined;
type FieldWithPossiblyUndefined<T, Key> =
| GetFieldType<Exclude<T, undefined>, Key>
| Extract<T, undefined>;
type IndexedFieldWithPossiblyUndefined<T, Key> =
| GetIndexedField<Exclude<T, undefined>, Key>
| Extract<T, undefined>;
export type GetFieldType<T, P> = P extends `${infer Left}.${infer Right}`
? Left extends keyof T
? FieldWithPossiblyUndefined<T[Left], Right>
: Left extends `${infer FieldKey}[${infer IndexKey}]`
? FieldKey extends keyof T
? FieldWithPossiblyUndefined<
IndexedFieldWithPossiblyUndefined<T[FieldKey], IndexKey>,
Right
>
: undefined
: undefined
: P extends keyof T
? T[P]
: P extends `${infer FieldKey}[${infer IndexKey}]`
? FieldKey extends keyof T
? IndexedFieldWithPossiblyUndefined<T[FieldKey], IndexKey>
: undefined
: undefined;
export const getAny = <
TData,
TPath extends string | number,
TDefault = GetFieldType<TData, TPath>,
>(
data: TData,
path: TPath,
defaultValue?: TDefault,
): GetFieldType<TData, TPath> | TDefault | any => {
if (typeof path === "number") {
return getAny(Object.values(data as any)[path], path);
}
const value = path
.toString()
.split(/[.[\]]/)
.filter(Boolean)
.reduce<GetFieldType<TData, TPath>>(
(value: any, key: string | number) => (value as any)?.[key],
data as any,
);
return value !== undefined ? value : (defaultValue as TDefault);
};
export const omitFrom = (input: any, keys: string[]): any => {
const output = { ...input };
const inputKeys = Object.keys(output);
inputKeys.forEach((inputKey: string) => {
if (keys.includes(inputKey) && output[inputKey]) {
delete output[inputKey];
} else {
const innerKeys = Object.keys(output[inputKey]);
innerKeys.forEach((innerKey: string) => {
if (keys.includes(innerKey)) {
delete output[inputKey][innerKey];
}
});
}
});
return output;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment