A sales dashboard I built for a client in Austin received customer records from two API endpoints. The problem was simple: Emma Johnson appeared twice because both systems returned the same customer ID. If I displayed that raw data, the dashboard showed duplicate rows and incorrect customer counts.
Removing duplicates from an array of objects in TypeScript needs more thought than removing duplicate strings or numbers. Objects have their own references in memory, so you must decide which property makes a record unique.
Below, I’ll show practical ways to remove duplicates from an array of objects in TypeScript, including reusable generic functions, complete code, and the approach I use most often in production projects.
Set Up the TypeScript Example
This guide assumes TypeScript 5+ and Node.js 18+. Create a file named remove-duplicates.ts, then run it with a TypeScript runner or compile it first.
npx tsc remove-duplicates.ts --target ES2022
node remove-duplicates.js
We will use a customer-reporting utility throughout this guide. An interface defines the required shape of an object. It helps TypeScript catch mistakes before your code runs.
interface Customer {
id: number;
name: string;
city: string;
email: string;
}
const customers: Customer[] = [
{
id: 101,
name: "Emma Johnson",
city: "Austin, Texas",
email: "emma.johnson@example.com"
},
{
id: 102,
name: "Daniel Miller",
city: "Chicago, Illinois",
email: "daniel.miller@example.com"
},
{
id: 101,
name: "Emma Johnson",
city: "Austin, Texas",
email: "emma.johnson@example.com"
},
{
id: 103,
name: "Olivia Carter",
city: "Seattle, Washington",
email: "olivia.carter@example.com"
}
];
console.log(customers);Sample output:
[
{
id: 101,
name: 'Emma Johnson',
city: 'Austin, Texas',
email: 'emma.johnson@example.com'
},
{
id: 102,
name: 'Daniel Miller',
city: 'Chicago, Illinois',
email: 'daniel.miller@example.com'
},
{
id: 101,
name: 'Emma Johnson',
city: 'Austin, Texas',
email: 'emma.johnson@example.com'
},
{
id: 103,
name: 'Olivia Carter',
city: 'Seattle, Washington',
email: 'olivia.carter@example.com'
}
]
The id field identifies each customer. That makes it the best property for detecting duplicate records. If you work with API data often, it also helps to understand how to convert JSON to an array in TypeScript before you clean the result.
Remove Duplicates from an Array of Objects in TypeScript With Set
The most beginner-friendly solution uses a Set. A Set stores only unique values. Instead of storing entire objects, store each object’s unique id.
This approach keeps the first customer record for every ID and removes later duplicates.
interface Customer {
id: number;
name: string;
city: string;
email: string;
}
const customers: Customer[] = [
{
id: 101,
name: "Emma Johnson",
city: "Austin, Texas",
email: "emma.johnson@example.com"
},
{
id: 102,
name: "Daniel Miller",
city: "Chicago, Illinois",
email: "daniel.miller@example.com"
},
{
id: 101,
name: "Emma Johnson",
city: "Austin, Texas",
email: "emma.johnson@example.com"
},
{
id: 103,
name: "Olivia Carter",
city: "Seattle, Washington",
email: "olivia.carter@example.com"
}
];
const seenCustomerIds = new Set<number>();
const uniqueCustomers = customers.filter((customer) => {
if (seenCustomerIds.has(customer.id)) {
return false;
}
seenCustomerIds.add(customer.id);
return true;
});
console.log(uniqueCustomers);Sample output:
[
{
id: 101,
name: 'Emma Johnson',
city: 'Austin, Texas',
email: 'emma.johnson@example.com'
},
{
id: 102,
name: 'Daniel Miller',
city: 'Chicago, Illinois',
email: 'daniel.miller@example.com'
},
{
id: 103,
name: 'Olivia Carter',
city: 'Seattle, Washington',
email: 'olivia.carter@example.com'
}
]
The filter() method creates a new array. For each customer, the callback checks whether the ID already exists in seenCustomerIds.
- If the ID exists, the callback returns
false, so TypeScript removes that customer. - If the ID does not exist, the code adds it to the Set and returns
true.
I use this pattern when I need readable code and want to keep the first occurrence. It works especially well in frontend applications that prepare API records before rendering a table.
Pro Tip: I always choose a stable identifier such as a database ID, UUID, or email address. Using a display name can silently remove different people who happen to share the same name.
For more array operations, see how to filter arrays in TypeScript and how to use the TypeScript forEach method on arrays.
Remove Duplicates from an Array of Objects in TypeScript With Map
Use a Map when you want the last duplicate record to win. A Map stores key-value pairs, where every key occurs only once.
This is useful when newer API data should replace older data. For example, a later record for Emma might include an updated city or email address.
interface Customer {
id: number;
name: string;
city: string;
email: string;
}
const customers: Customer[] = [
{
id: 101,
name: "Emma Johnson",
city: "Austin, Texas",
email: "emma.johnson@example.com"
},
{
id: 102,
name: "Daniel Miller",
city: "Chicago, Illinois",
email: "daniel.miller@example.com"
},
{
id: 101,
name: "Emma Johnson",
city: "Dallas, Texas",
email: "emma.johnson@example.com"
},
{
id: 103,
name: "Olivia Carter",
city: "Seattle, Washington",
email: "olivia.carter@example.com"
}
];
const customerMap = new Map<number, Customer>();
for (const customer of customers) {
customerMap.set(customer.id, customer);
}
const uniqueCustomers = Array.from(customerMap.values());
console.log(uniqueCustomers);Sample output:
[
{
id: 101,
name: 'Emma Johnson',
city: 'Dallas, Texas',
email: 'emma.johnson@example.com'
},
{
id: 102,
name: 'Daniel Miller',
city: 'Chicago, Illinois',
email: 'daniel.miller@example.com'
},
{
id: 103,
name: 'Olivia Carter',
city: 'Seattle, Washington',
email: 'olivia.carter@example.com'
}
]
The second record for Emma replaces the first because both use 101 as the Map key. Then Array.from() converts the Map values back into a normal array.
A Map is a strong option in a Node.js script, backend API, or data-import job where later records contain fresher data. Learn more about creating a Map from an array in TypeScript when you need to build richer lookup logic.
Remove Duplicates by Any Object Property
Hard-coding customer.id works for one data model. A reusable generic function works for many models.
A generic lets you write a function once while preserving the types of different objects. In this case, the function accepts an array and the property that defines uniqueness.
function removeDuplicatesByKey<T, K extends keyof T>(
items: T[],
key: K
): T[] {
const seenValues = new Set<T[K]>();
return items.filter((item) => {
const value = item[key];
if (seenValues.has(value)) {
return false;
}
seenValues.add(value);
return true;
});
}
interface Customer {
id: number;
name: string;
city: string;
email: string;
}
const customers: Customer[] = [
{
id: 101,
name: "Emma Johnson",
city: "Austin, Texas",
email: "emma.johnson@example.com"
},
{
id: 102,
name: "Daniel Miller",
city: "Chicago, Illinois",
email: "daniel.miller@example.com"
},
{
id: 103,
name: "Olivia Carter",
city: "Seattle, Washington",
email: "emma.johnson@example.com"
},
{
id: 104,
name: "Marcus Lee",
city: "Denver, Colorado",
email: "marcus.lee@example.com"
}
];
const uniqueCustomersByEmail = removeDuplicatesByKey(customers, "email");
console.log(uniqueCustomersByEmail);
Sample output:
[
{
id: 101,
name: 'Emma Johnson',
city: 'Austin, Texas',
email: 'emma.johnson@example.com'
},
{
id: 102,
name: 'Daniel Miller',
city: 'Chicago, Illinois',
email: 'daniel.miller@example.com'
},
{
id: 104,
name: 'Marcus Lee',
city: 'Denver, Colorado',
email: 'marcus.lee@example.com'
}
]
Here, TypeScript checks that "email" exists on the Customer interface. If you try removeDuplicatesByKey(customers, “phoneNumber”), TypeScript raises a compile-time error because phoneNumber does not exist.
The keyof T part means “any valid property name from this object type.” It gives you type safety without writing a separate duplicate-removal function for every interface.
This pattern fits shared utility modules, React data hooks, Express API services, and automation scripts. If you want to go deeper, read about the TypeScript keyof operator and generic object types in TypeScript.
Remove Duplicates Using Multiple Properties
Sometimes one property does not define a duplicate. A customer import might treat records as duplicates only when both name and city match.
For that case, create a combined key from the properties you want to compare. Use a separator that cannot appear in your values, or encode each value safely.
interface Customer {
id: number;
name: string;
city: string;
email: string;
}
const customers: Customer[] = [
{
id: 101,
name: "Emma Johnson",
city: "Austin, Texas",
email: "emma.johnson@example.com"
},
{
id: 102,
name: "Daniel Miller",
city: "Chicago, Illinois",
email: "daniel.miller@example.com"
},
{
id: 103,
name: "Emma Johnson",
city: "Austin, Texas",
email: "emma.j@example.com"
},
{
id: 104,
name: "Emma Johnson",
city: "Boston, Massachusetts",
email: "emma.boston@example.com"
}
];
const seenCustomerKeys = new Set<string>();
const uniqueCustomers = customers.filter((customer) => {
const duplicateKey = JSON.stringify([
customer.name.trim().toLowerCase(),
customer.city.trim().toLowerCase()
]);
if (seenCustomerKeys.has(duplicateKey)) {
return false;
}
seenCustomerKeys.add(duplicateKey);
return true;
});
console.log(uniqueCustomers);Sample output:
[
{
id: 101,
name: 'Emma Johnson',
city: 'Austin, Texas',
email: 'emma.johnson@example.com'
},
{
id: 102,
name: 'Daniel Miller',
city: 'Chicago, Illinois',
email: 'daniel.miller@example.com'
},
{
id: 104,
name: 'Emma Johnson',
city: 'Boston, Massachusetts',
email: 'emma.boston@example.com'
}
]
The .trim() method removes extra spaces, while .toLowerCase() makes the comparison case-insensitive. JSON.stringify() creates a stable string key from both normalized values.
I prefer this approach over comparing each object manually. It stays readable as you add properties, and it prevents mistakes in duplicate logic. You can pair this with filtering an array of objects by multiple properties in TypeScript when your tool also needs search filters.
Why new Set(objects) Does Not Remove Object Duplicates
This code looks correct but does not remove separate objects with matching values:
interface Customer {
id: number;
name: string;
}
const customers: Customer[] = [
{ id: 101, name: "Emma Johnson" },
{ id: 101, name: "Emma Johnson" }
];
const uniqueCustomers = [...new Set(customers)];
console.log(uniqueCustomers);Sample output:
[
{ id: 101, name: 'Emma Johnson' },
{ id: 101, name: 'Emma Johnson' }
]
You can see the output in the screenshot below.

JavaScript compares objects by reference, not by their contents. These two customer objects contain the same values, but they occupy different places in memory. The Set sees two different references.
A Set only removes duplicate objects when the array contains the same object reference twice.
interface Customer {
id: number;
name: string;
}
const emma: Customer = { id: 101, name: "Emma Johnson" };
const customers: Customer[] = [
emma,
emma
];
const uniqueCustomers = [...new Set(customers)];
console.log(uniqueCustomers);Sample output:
[
{ id: 101, name: 'Emma Johnson' }
]
You can see the output in the screenshot below.

This behavior often surprises developers working with API data. API calls usually create new object references, even when the records look identical. Use a unique property, a composite key, or a Map instead.
Which Approach Should You Use?
Use the simplest approach that matches your business rule.
| Requirement | Best approach | Result |
|---|---|---|
| Keep the first record for each ID | Set with filter() | Preserves the first matching object |
| Keep the latest record for each ID | Map | Replaces earlier objects with later ones |
| Reuse logic across many object types | Generic removeDuplicatesByKey() | Gives type-safe, reusable code |
| Compare more than one property | Set with a composite key | Removes matches based on multiple values |
| Remove repeated object references only | new Set(objects) | Does not compare object contents |
For most dashboard, API, and data-import work, start with the Set and filter() pattern. It is fast, readable, and clear about which record wins.
Things to Keep in Mind
- Choose a real unique key: Prefer database IDs, UUIDs, or verified email addresses over display names, which can repeat.
- Normalize text values: Use
trim()andtoLowerCase()before comparing user-entered names, emails, or locations. - Avoid
any: Define an interface or type for incoming data so TypeScript can catch missing properties early. See why you should avoid the TypeScript any type. - Handle missing values: Decide how to treat
null,undefined, and empty strings before generating duplicate keys. Do not let incomplete API data merge unrelated records. - Keep performance linear: Set and Map solutions usually process each item once, so they work well for large arrays. Avoid nested
filter()andfind()calls for large reports. - Preserve source data:
filter()returns a new array and leaves your original array unchanged, which helps prevent unexpected UI and API bugs.
Frequently Asked Questions
How do I remove duplicates from an array of objects in TypeScript by ID?
Use a Set to track IDs while filtering the array. Keep an object only when its ID has not appeared before. This preserves the first object for every ID.
Can I use Set directly on an array of objects?
You can, but it removes only repeated references to the same object. It does not compare object properties such as id, name, or email. Use a Set of property values instead.
How do I keep the last duplicate object in TypeScript?
Create a Map and use the unique property as its key. Each later map.set() call replaces the previous value for that key. Convert map.values() into an array when you finish.
How do I remove duplicates using two properties?
Create a composite key from both properties, then store that key in a Set. Normalize strings first when case or extra spaces should not matter. For example, combine a customer’s normalized name and city.
Does removing duplicates change the original TypeScript array?
The Set with filter() approach does not change the original array. It returns a new array with unique objects. A Map-based approach also returns a new array after you call Array.from().
What is the fastest way to remove duplicate objects in TypeScript?
A Set or Map provides an efficient solution for most applications because each item needs one lookup and one insert. The right choice depends on whether you want to keep the first or last matching record.
You now know how to remove duplicates from an array of objects in TypeScript using Set, Map, generic functions, and composite keys. Start with the Set and filter() method for most cases, then use Map when newer duplicate records should replace older ones. I hope you found this article helpful.
You May Also Like
- Get unique values from an array of objects in TypeScript
- Work with arrays of objects in TypeScript
- Find an object in an array by property in TypeScript
- Sort an array of objects by property in TypeScript
- Update an object in an array in TypeScript

Bijay Kumar is an experienced Python and AI professional who enjoys helping developers learn modern technologies through practical tutorials and examples. His expertise includes Python development, Machine Learning, Artificial Intelligence, automation, and data analysis using libraries like Pandas, NumPy, TensorFlow, Matplotlib, SciPy, and Scikit-Learn. At PythonGuides.com, he shares in-depth guides designed for both beginners and experienced developers. More about us.