ThisCalculator

Everyday

Combine TypeScript Object Arrays by ID: Merge & Spread

Updated · Standard formula, shown below

This guide shows you how to combine two or more TypeScript object arrays into one, matching items by a common ID field. You’ll learn three practical approaches—using the spread operator, using a Map for efficiency, and a simple merge with a loop—so you can pick the one that fits your data size and style. No external libraries are required, just a basic understanding of TypeScript interfaces and array methods.

What You’ll Need

  • Node.js installed (or a browser console) to run TypeScript code
  • A TypeScript compiler or a tool like ts-node, or just use JavaScript after removing type annotations
  • Two or more arrays of objects that share a common ID field (e.g., id, userId)
  • Basic familiarity with TypeScript types and array methods like map, find, and reduce

Step-by-Step

  1. Define your object types. Start by creating interfaces that describe the shape of your objects. For example:
    interface User { id: number; name: string; }
    interface UserEmail { id: number; email: string; }
  2. Create your source arrays. Have two arrays that you want to merge. For instance:
    const users: User[] = [
      { id: 1, name: 'Alice' },
      { id: 2, name: 'Bob' }
    ];
    const emails: UserEmail[] = [
      { id: 1, email: 'alice@example.com' },
      { id: 2, email: 'bob@example.com' }
    ];
  3. Choose your merge strategy. There are three common ways:
    • Spread with find (simple, small arrays): Use map over the first array and spread the matching object from the second array.
    • Map-based (efficient for large arrays): Build a lookup map from the second array, then map over the first array.
    • Reduce/loop (when you need more control): Iterate manually and combine objects.
  4. Implement the spread + find method. For each object in the first array, find the matching object in the second array and spread both into a new object:
    const merged = users.map(user => ({
      ...user,
      ...emails.find(email => email.id === user.id)
    }));
    // Result: [{ id: 1, name: 'Alice', email: 'alice@example.com' }, ...]

    Note: This is O(n*m) and can be slow for large arrays.

  5. Implement the Map-based method (recommended for performance). Create a Map from the second array keyed by ID, then map over the first array:
    const emailMap = new Map(emails.map(email => [email.id, email]));
    const merged = users.map(user => ({
      ...user,
      ...emailMap.get(user.id)
    }));

    This runs in O(n+m) time.

  6. Handle missing matches. If an ID in the first array doesn’t exist in the second, the spread will add undefined properties. To avoid that, filter or conditionally spread:
    const merged = users.map(user => {
      const email = emailMap.get(user.id);
      return email ? { ...user, ...email } : user;
    });
  7. Merge more than two arrays. You can chain the same technique. For example, to merge three arrays, create a map from the third array as well and spread it in the same map callback.
  8. Use a generic helper function. To make it reusable, write a function that accepts two arrays and a key selector:
    function mergeById<T extends { id: number }, U>(arr1: T[], arr2: U[]): (T & U)[] {
      const map = new Map(arr2.map(item => [(item as any).id, item]));
      return arr1.map(item => ({ ...item, ...map.get(item.id) }));
    }
  9. Test with edge cases. Try arrays with different lengths, duplicate IDs, or missing IDs to ensure your logic handles them as expected.

Common Mistakes

  • Assuming both arrays have the same length. If one array is shorter, the spread will produce undefined for missing properties. Always check for existence.
  • Using a non-unique ID. If IDs repeat, the Map will keep only the last occurrence, which may not be what you want. Ensure your ID field is unique.
  • Mutating the original arrays. The spread operator creates a new object, but if you use Object.assign on the original object, you might accidentally modify it. Always create new objects.
  • Forgetting that spread is shallow. If your objects contain nested objects or arrays, the spread copies references, not deep clones. Changes to nested data will affect the original.
  • Using find inside a loop for large arrays. This leads to O(n²) performance. Use a Map for anything beyond a few hundred items.

Tips

  • Use a Map for performance. It’s almost always the best choice for real-world data.
  • Define a type for the merged result. Use intersection types like User & UserEmail to get type safety.
  • Consider using a library like Lodash’s merge or unionBy if you’re already using it, but the native approach is lightweight and sufficient.
  • If you need to merge by a different key (e.g., slug), adjust the Map key accordingly.
  • For immutable updates in state management, always return new arrays and objects.

Troubleshooting

  • Merged result has undefined values. This happens when a matching ID isn’t found. Add a conditional spread as shown in step 6.
  • TypeScript complains about the spread type. Ensure your interfaces are compatible. Use intersection types or cast if necessary.
  • The order of properties is unexpected. The spread order determines property precedence. Later spreads override earlier ones. Put the base object first, then the override.
  • Performance is slow for large arrays. Switch from find to a Map.
  • Duplicate IDs cause data loss. Decide on a strategy: keep the first, last, or combine them manually. The Map approach keeps the last.

Frequently Asked Questions

Can I merge arrays by ID without mutating the original arrays?

Yes, the spread operator creates new objects, so the original arrays remain unchanged. Just ensure you don’t assign to the original objects.

What if the ID field has a different name in each array?

You can map the second array to use the same key as the first, or adjust the lookup logic. For example, if one uses _id and the other id, you can do arr2.map(item => ({ ...item, id: item._id })) before building the Map.

How do I merge more than two arrays?

Chain the same technique: create a Map for the third array and spread it in the same callback. Or reduce over an array of arrays.

Is there a way to merge arrays by ID without using a Map?

Yes, you can use nested loops or reduce, but the Map is the most efficient. For very small arrays, find is fine.

Does the spread operator deep clone nested objects?

No, it’s a shallow copy. If you need deep merging, use a utility like Lodash’s merge or write a recursive function.

Can I use this technique with arrays of objects that have optional properties?

Yes, TypeScript will handle optional properties fine. Just be aware that missing properties may result in undefined.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.