uniqueDeepBy
Removes deeply equal duplicate values from an array.
1/**
2 * Removes deeply equal duplicate values from an array.
3 *
4 * @param arr - The array of items.
5 * @returns A new array with deeply equal duplicates removed.
6 */
7export function uniqueDeep<T>(arr: T[]): T[] {
8 return arr.filter((item, index) => {
9 return (
10 arr.findIndex(other => deepEqual(item, other)) === index
11 );
12 });
13}
Deep equality comparison
Unlike shallow comparison (
===
), this utility usesdeepEqual()
to detect structural or nested object duplicates, which is essential for deeply nested data structures.Intuitive filtering logic
Leverages
Array.prototype.filter()
in combination withfindIndex()
to preserve the first occurrence of each deeply equal value, maintaining array order.Supports complex data types
Works for arrays of arrays, arrays of objects, or any recursively structured data.
Pure and immutable
Produces a new array without mutating the original, aligning with best practices in functional programming and state management.
Tests | Examples
1test('uniqueDeepBy - removes duplicates by nested key', () => {
2 const data = [
3 { user: { id: 1, name: 'Alice' } },
4 { user: { id: 2, name: 'Bob' } },
5 { user: { id: 1, name: 'Alice' } },
6 ];
7 const result = uniqueDeepBy(data, item => item.user);
8 expect(result).toEqual([
9 { user: { id: 1, name: 'Alice' } },
10 { user: { id: 2, name: 'Bob' } },
11 ]);
12});
13
14test('uniqueDeepBy - removes duplicate arrays by slice', () => {
15 const arr = [
16 [1, 2, 3],
17 [1, 2, 3],
18 [2, 3, 4],
19 ];
20 const result = uniqueDeepBy(arr, x => x.slice(0, 2));
21 expect(result).toEqual([
22 [1, 2, 3],
23 [2, 3, 4],
24 ]);
25});
26
27test('uniqueDeepBy - works with primitive keys', () => {
28 const items = [{ id: 1 }, { id: 2 }, { id: 1 }];
29 expect(uniqueDeepBy(items, item => item.id)).toEqual([
30 { id: 1 },
31 { id: 2 },
32 ]);
33});
34
35test('uniqueDeepBy - handles empty array', () => {
36 expect(uniqueDeepBy([], item => item)).toEqual([]);
37});
Common Use Cases
Cleaning normalized API responses
When APIs return data with repeated nested structures, this utility helps remove redundant entries before further processing.
React state deduplication
Helps avoid unnecessary re-renders by filtering out deeply equal values when updating complex state arrays (e.g., filtering events, logs, or form states).
Data transformation pipelines
Useful in ETL (Extract, Transform, Load) processes or client-side data prep steps, especially when merging user data or syncing with offline stores.
Sanitizing form inputs or nested payloads
Ensures that repeated user inputs or auto-generated entries (e.g. dynamic forms) are filtered down to one version structurally.