How to Find the Difference Between Two Arrays in TypeScript
The runtime logic for array difference in TypeScript is identical to plain JavaScript - filter one array against a Set built from the other. What TypeScript adds is a way to make that logic generic and type-safe, so it works correctly across every array type in your codebase without copy-pasting the same function for strings, numbers, and object shapes.
Quick answer
Write one generic helper: function difference. TypeScript infers T from the call site, so it works for string[], number[], or any other array type with full type checking. For arrays of objects, add a keyof T selector to compare by a specific field instead of the whole object.
Need the same thing in another language?
See the full reference for JavaScript, Python, SQL, Java, and more.
A generic, typed difference function
function difference<T>(a: readonly T[], b: readonly T[]): T[] {
const setB = new Set(b);
return a.filter(x => !setB.has(x));
}
const a = ['apple', 'banana', 'cherry'];
const b = ['banana', 'date'];
const aOnly = difference(a, b);
console.log(aOnly); // ['apple', 'cherry'], typed as string[] Using readonly T[] instead of T[] for the parameters is a small but meaningful improvement: it lets the function accept both mutable arrays and readonly/as const arrays, and it documents that the function won't mutate what you pass in. T is inferred from the call - you never need to write difference<string>(a, b) explicitly.
Comparing arrays of objects by key
interface User {
id: number;
name: string;
}
function differenceBy<T, K extends keyof T>(a: T[], b: T[], key: K): T[] {
const setB = new Set(b.map(x => x[key]));
return a.filter(x => !setB.has(x[key]));
}
const usersA: User[] = [{ id: 1, name: 'Ana' }, { id: 2, name: 'Ben' }];
const usersB: User[] = [{ id: 2, name: 'Ben' }];
const onlyInA = differenceBy(usersA, usersB, 'id');
console.log(onlyInA); // [{ id: 1, name: 'Ana' }] The K extends keyof T constraint means the compiler checks that key is a real property of T - passing 'email' when User has no email field is a compile error, not a bug you find at runtime. This is the version worth reaching for whenever you're diffing arrays of objects, since two objects are never === to each other even with identical properties.
The ES2024 Set.prototype.difference() method
// tsconfig.json: "lib": ["ES2024"] or "esnext" const a = new Set(['apple', 'banana', 'cherry']); const b = new Set(['banana', 'date']); const aOnly: Set<string> = a.difference(b); console.log([...aOnly]); // ['apple', 'cherry']
This is typed correctly once your tsconfig.json lib array includes ES2024 (or the rolling esnext), but it still depends on the runtime actually supporting it - check your minimum supported Node or browser version before relying on it without a polyfill. It also returns a Set, not an array, and like every set-based approach it drops duplicates and doesn't preserve the original order of a.
Symmetric difference, typed
function symmetricDifference<T>(a: readonly T[], b: readonly T[]): T[] {
const setA = new Set(a);
const setB = new Set(b);
return [
...a.filter(x => !setB.has(x)),
...b.filter(x => !setA.has(x)),
];
}
console.log(symmetricDifference(['apple', 'banana'], ['banana', 'date']));
// ['apple', 'date'] Same generic pattern as the difference function above, just running the filter in both directions and concatenating the results. This is the TypeScript equivalent of what's covered in more depth in the JavaScript array difference guide - the runtime code is the same, TypeScript just adds the generic type signature on top.
Just need the answer, not the code? Paste both lists.
Open Compare 2 Lists →Frequently Asked Questions
What is the typed way to find the difference between two arrays in TypeScript?
function difference<T>(a: T[], b: T[]): T[] { const setB = new Set(b); return a.filter(x => !setB.has(x)); }. TypeScript infers T from the arguments, so difference(['a','b'], ['b']) returns a correctly typed string[] with no annotations needed at the call site.Does this work with readonly arrays?
readonly T[] instead of T[] lets the function accept both mutable arrays and ReadonlyArray<T> / as const arrays without a cast, and it correctly signals that the function never mutates its inputs.Is there a built-in Set.prototype.difference() in TypeScript?
lib target (ES2024 or the rolling esnext) in tsconfig.json to have it typed. new Set(a).difference(new Set(b)) works once your lib includes it and your runtime (recent Node, Chrome, Firefox) supports it. It returns a Set<T>, not an array, and drops order and duplicates.How do I compare two arrays of objects by a specific key in TypeScript?
keyof T selector so the compiler checks the key exists on the type: function differenceBy<T, K extends keyof T>(a: T[], b: T[], key: K): T[] { const setB = new Set(b.map(x => x[key])); return a.filter(x => !setB.has(x[key])); }. Passing a key that doesn't exist on T is now a compile error instead of a silent runtime bug.Why does my array difference return an empty type or "never"?
const a = ['x', 'y'] as const) with a non-generic helper that expects string[]. Keep the function generic (T[], not a hardcoded type) and let TypeScript infer T from both arguments rather than annotating one side manually.How do I do a case-insensitive array difference in TypeScript?
const setB = new Set(b.map(x => x.toLowerCase())); const aOnly = a.filter(x => !setB.has(x.toLowerCase()));. The types stay string[] throughout since .toLowerCase() returns a string.Is the difference between TypeScript and JavaScript array difference just the type annotations?
Set/filter JavaScript. See the JavaScript array difference guide for the identical runtime approaches. What TypeScript adds is compile-time safety: catching a typo'd key name, an accidental string[] vs number[] mismatch, or a missing generic before the code ever runs.