diff --git a/src/array.ts b/src/array.ts index 173bfc8..644bc97 100644 --- a/src/array.ts +++ b/src/array.ts @@ -69,6 +69,20 @@ export function uniq(array: readonly T[]): T[] { return Array.from(new Set(array)) } +/** + * Unique an Array by a custom equality function + * + * @category Array + */ +export function uniqueBy(array: readonly T[], equalFn: (a: any, b: any) => boolean): T[] { + return array.reduce((acc: T[], cur: any) => { + const index = acc.findIndex((item: any) => equalFn(cur, item)) + if (index === -1) + acc.push(cur) + return acc + }, []) +} + /** * Get last item * diff --git a/src/base.ts b/src/base.ts index 04ab0e5..03e5656 100644 --- a/src/base.ts +++ b/src/base.ts @@ -3,4 +3,10 @@ export const assert = (condition: boolean, message: string): asserts condition = throw new Error(message) } export const toString = (v: any) => Object.prototype.toString.call(v) +export const getTypeName = (v: any) => { + if (v === null) + return 'null' + const type = toString(v).slice(8, -1).toLowerCase() + return typeof v === 'object' || typeof v === 'function' ? type : typeof v +} export const noop = () => {} diff --git a/src/equal.ts b/src/equal.ts new file mode 100644 index 0000000..93a4cbc --- /dev/null +++ b/src/equal.ts @@ -0,0 +1,27 @@ +import { getTypeName } from './base' + +export function isDeepEqual(value1: any, value2: any): boolean { + const type1 = getTypeName(value1) + const type2 = getTypeName(value2) + if (type1 !== type2) + return false + + if (type1 === 'array') { + if (value1.length !== value2.length) + return false + + return value1.every((item: any, i: number) => { + return isDeepEqual(item, value2[i]) + }) + } + if (type1 === 'object') { + const keyArr = Object.keys(value1) + if (keyArr.length !== Object.keys(value2).length) + return false + + return keyArr.every((key: string) => { + return isDeepEqual(value1[key], value2[key]) + }) + } + return value1 === value2 +}