To check if a TypeScript array contains a specific value, call includes(): cities.includes("Denver") returns true or false. That works for strings, numbers and booleans. For an array of objects it will not, because includes() compares by reference, so you test a property with some() instead: orders.some(o => o.id === "ORD-1001"). This guide covers both, plus case-insensitive and partial matches, checking several values at once, the as const error that sends people here, and what to use when the array is long.
Every example was compiled and run with TypeScript 5.2.2 and Node.js v22.22.2 in the Windows Command Prompt, with tsc --target es2022 --lib es2023,dom --strict file.ts and then node file.js. The output is the real output. Reference: Array.prototype.includes() on MDN.
Check if a TypeScript array contains a value
includes() answers the question directly and reads as the sentence you were thinking. It takes an optional second argument, the index to start from, which is occasionally handy and often surprising:
const cities: string[] = ["Austin", "Denver", "Seattle"];
console.log(cities.includes("Denver")); // true
console.log(cities.includes("Chicago")); // false
const totals: number[] = [249.99, 89.5, 430];
console.log(totals.includes(430));
// start the search from a position, as indexOf does
console.log(cities.includes("Austin", 1)); // false: the search starts at index 1
// the old way, still everywhere in existing code
console.log(cities.indexOf("Seattle") !== -1);
Output:
true
false
true
false
true

includes() gives you a boolean; indexOf() !== -1 is the older spelling.| What you need | Use |
|---|---|
| Does it contain this value? | items.includes(value) |
| Does it contain an object with this id? | items.some(i => i.id === id) |
| Where is it? | items.indexOf(value) or findIndex() |
| Give me the matching item | items.find(i => ...) |
| Ignoring case | items.some(i => i.toLowerCase() === v.toLowerCase()) |
| Any or all of several values | wanted.some(...) / wanted.every(...) |
| Many lookups on a long array | new Set(items).has(value) |
includes() versus indexOf(): NaN and holes
These two are not interchangeable. indexOf() uses strict equality, and NaN === NaN is false, so it can never find one. includes() uses SameValueZero, which treats NaN as equal to itself, and it also sees the empty slots in a sparse array as undefined:
const readings: number[] = [12.5, NaN, 7];
console.log(readings.includes(NaN)); // true
console.log(readings.indexOf(NaN)); // -1: indexOf uses ===
console.log(readings.some(Number.isNaN)); // the explicit way to ask
const sparse: (number | undefined)[] = [1, 2, 3];
delete sparse[1]; // a hole, not an undefined value
console.log(sparse.includes(undefined)); // true: includes treats a hole as undefined
console.log(sparse.indexOf(undefined)); // -1: indexOf skips holes
console.log([0].includes(-0), Object.is(0, -0));
Output:
true
-1
true
true
-1
true false

NaN, and empty slots.Arrays of objects: use some()
includes() asks “is this exact object in the array”, which is almost never the question. Two objects with identical properties are different values, so test a property instead. If you want the object rather than a yes or no, find() is the one you want:
interface Order {
id: string;
city: string;
}
const orders: Order[] = [
{ id: "ORD-1001", city: "Austin" },
{ id: "ORD-1002", city: "Denver" },
];
// includes() compares references, so an equal-looking object is not found
console.log(orders.includes({ id: "ORD-1001", city: "Austin" }));
// the one you already hold IS found
console.log(orders.includes(orders[0]));
// for objects, test a property instead
console.log(orders.some(order => order.id === "ORD-1001"));
console.log(orders.some(order => order.city === "Seattle"));
// and when you need the object itself, not just a yes or no
const found = orders.find(order => order.id === "ORD-1002");
console.log(found?.city ?? "not found");
Output:
false
true
true
false
Denver

false, third line true: same data, different question.Case-insensitive and partial matches
Two different questions get confused here. includes() on the array asks whether an element equals your value; some() with includes() on each element asks whether any element contains your text. Trim input that came from a form, and lowercase both sides when case should not matter, as in a search box over an array of objects:
const cities: string[] = ["Austin", "Denver", "Seattle"];
// case-insensitive: compare like with like
const input = "denver";
console.log(cities.some(city => city.toLowerCase() === input.toLowerCase()));
// "contains a value" versus "contains a value that contains this text"
console.log(cities.includes("Aus")); // false: no exact match
console.log(cities.some(city => city.includes("Aus"))); // true: partial match
// does the array contain ANY of these, or ALL of them?
const wanted = ["Denver", "Chicago"];
console.log(wanted.some(city => cities.includes(city)));
console.log(wanted.every(city => cities.includes(city)));
// trim before comparing when the value came from a form
const typed = " Seattle ";
console.log(cities.includes(typed), cities.includes(typed.trim()));
Output:
true
false
true
true
false
false true
The as const error you probably came for
Declaring a list of allowed values with as const makes it a readonly array of literal types. That is what you want for the type, but then includes() refuses your plain string, because a string is not one of those three literals:
const roles = ["admin", "editor", "viewer"] as const;
function isRole(value: string): boolean {
return roles.includes(value); // value is a plain string
}
console.log(isRole("admin"));
tsc output:
contains_union_error.ts(4,25): error TS2345: Argument of type 'string' is not assignable to parameter of type '"admin" | "editor" | "viewer"'.

value might be any string at all.The fix is a type guard. Widen the array to readonly string[] for the call, and declare the return type as value is Role so the caller gets the narrowed type for free:
const roles = ["admin", "editor", "viewer"] as const;
type Role = (typeof roles)[number]; // "admin" | "editor" | "viewer"
// a type guard: it answers the question AND narrows the value for the caller
function isRole(value: string): value is Role {
return (roles as readonly string[]).includes(value);
}
const input = "editor";
if (isRole(input)) {
const role: Role = input; // narrowed, no cast needed
console.log("valid role:", role);
}
console.log(isRole("admin"), isRole("owner"));
Output:
valid role: editor
true false
Long arrays and repeated lookups
includes() scans from the start every time. One lookup on a short array is nothing; thousands of lookups on a long one add up, and that is when a Set earns its keep, exactly as it does when collecting unique values:
const ids: string[] = Array.from({ length: 50_000 }, (_, i) => `ID-${i}`);
const lookups: string[] = Array.from({ length: 5_000 }, (_, i) => `ID-${i * 9}`);
function time(label: string, fn: () => number): void {
fn(); // warm-up run
const start = performance.now();
const hits = fn();
console.log(label.padEnd(24), (performance.now() - start).toFixed(1).padStart(8), "ms", "found", hits);
}
time("includes()", () => lookups.filter(id => ids.includes(id)).length);
const set = new Set(ids);
time("Set.has()", () => lookups.filter(id => set.has(id)).length);

Build the Set once, outside the loop. Building it inside the predicate costs more than the scan you were trying to avoid.
More TypeScript array guides worth reading:
- Find an object in a TypeScript array
- Filter arrays in TypeScript
- Check if an array is null or empty
- Loop through an array
- Remove duplicates from an array
Frequently asked questions
How do I check if a TypeScript array contains a value?
Use items.includes(value). It returns true or false and works for strings, numbers and booleans.
Why does includes() not find my object?
It compares by reference. Two objects with the same properties are different values, so use items.some(i => i.id === id).
What is the difference between includes() and indexOf()?
includes() returns a boolean and can find NaN; indexOf() returns a position and uses strict equality, so it cannot.
How do I check if an array contains a value ignoring case?
items.some(item => item.toLowerCase() === value.toLowerCase()). Trim the value too if it came from user input.
Why does includes() give an error with an as const array?
The array holds literal types, and your argument is a wider string. Use a type guard that casts to readonly string[] internally.
How do I check whether an array contains any of several values?
wanted.some(value => items.includes(value)) for any, and wanted.every(...) for all of them.
Is includes() slow on a large array?
It scans the array each time. For many lookups, build a Set once and call has() instead.

Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn