unionBy
Returns an array of distinct elements from both arrays using a key selector. If elements from both arrays share the same key, only the first occurrence is kept.
1/**
2 * Returns an array of distinct elements from both arrays using a key selector.
3 * If elements from both arrays share the same key, only the first occurrence is kept.
4 *
5 * @param a - First array.
6 * @param b - Second array.
7 * @param keyFn - Function to extract a comparable key from each element.
8 * @returns A new array with unique elements by key.
9 */
10export function unionBy<T>(
11 a: T[],
12 b: T[],
13 keyFn: (item: T) => string | number
14): T[] {
15 const seen = new Set<string | number>();
16 const result: T[] = [];
17
18 for (const item of [...a, ...b]) {
19 const key = keyFn(item);
20 if (!seen.has(key)) {
21 seen.add(key);
22 result.push(item);
23 }
24 }
25
26 return result;
27}
Custom key-based uniqueness
Allows merging arrays while ensuring uniqueness based on a derived key (e.g.
id
,slug
,name
), not just strict equality. This is more flexible than the standardSet
-basedunion
.Order of first occurrence preserved
Keeps the first occurrence of each unique key from the merged input arrays, which is often desirable in UI lists, priority-based logic, or user-defined preferences.
Efficient one-pass filtering
Performs all operations in a single loop with
O(n)
complexity thanks to theSet
for tracking seen keys.Pure and immutable
Does not modify the input arrays and produces a new result array.
Works with both primitives and objects
Ideal for de-duplicating object arrays where equality must be derived from a specific property.
Tests | Examples
1test('unionBy - with objects and id key', () => {
2 const arr1 = [{ id: 1 }, { id: 2 }];
3 const arr2 = [{ id: 2 }, { id: 3 }];
4 expect(unionBy(arr1, arr2, item => item.id)).toEqual([
5 { id: 1 },
6 { id: 2 },
7 { id: 3 },
8 ]);
9});
10
11test('unionBy - using length as key', () => {
12 const arr1 = ['a', 'bb'];
13 const arr2 = ['ccc', 'dd'];
14 expect(unionBy(arr1, arr2, str => str.length)).toEqual(['a', 'bb', 'ccc']);
15});
16
17test('unionBy - one array empty', () => {
18 expect(unionBy([], [{ id: 1 }], item => item.id)).toEqual([{ id: 1 }]);
19});
20
21test('unionBy - both arrays empty', () => {
22 expect(unionBy([], [], item => item)).toEqual([]);
23});
Common Use Cases
Merging API results or paginated data
Combine responses from multiple pages or endpoints while eliminating duplicates based on a consistent identifier.
Deduplicating items in UI components
Useful when rendering a merged feed of cards, suggestions, or search results with potential overlap.
Data normalization
Aggregate data from different sources and ensure each entity appears only once by key.
Building unique dropdowns or filters
Construct a deduplicated list of options based on object keys.