How to Filter Arrays in TypeScript

When I build sales dashboards, API collectors, or Node.js automation scripts, I often receive far more data than the screen or next step needs. A customer list may include inactive accounts, an order feed may contain canceled orders, or a report may need only sales above a target.

That is where filtering arrays in TypeScript becomes useful. You can keep only the values that match a rule while preserving the original array, which makes your code safer and easier to reuse.

In this guide, I will show you how to filter string, number, and object arrays in TypeScript, handle missing values safely, and write reusable typed filters.

What Does Filtering an Array Mean?

An array is an ordered collection of values. For example, a sales application might store order totals in a number[], while a customer dashboard may store customer records in an array of objects.

The TypeScript filter() method checks every item in an array against a condition. It returns a new array containing only the items where the condition returns true.

This is important: filter() does not change the original array. That makes it different from methods such as splice(), which removes items directly from the existing array. If you need a quick refresher on array setup, see this guide on how to initialize an array in TypeScript.

Here is the basic syntax:

const filteredArray = originalArray.filter((item) => {
return condition;
});

You can also write it as a one-line arrow function:

const filteredArray = originalArray.filter((item) => condition);

The callback function receives one array item at a time. It must return:

  • true to keep that item
  • false to exclude that item

Filter Arrays in TypeScript with filter()

The most common way to filter an array in TypeScript is with the built-in filter() method. It works in browser applications, Node.js TypeScript scripts, server-side APIs, and frontend frameworks.

Let’s use a simple sales-reporting example throughout this article. Imagine that Ethan Parker runs a small online store in Austin, Texas. His reporting script receives order values, customer details, and order statuses from an internal API.

Filter a Number Array

Suppose you need to show only orders worth $100 or more. You can filter the order totals with a comparison condition.

const orderTotals: number[] = [45, 125, 89, 220, 100, 67];

const largeOrders: number[] = orderTotals.filter((total) => total >= 100);

console.log("All orders:", orderTotals);
console.log("Orders worth $100 or more:", largeOrders);

Sample output:

All orders: [ 45, 125, 89, 220, 100, 67 ]
Orders worth $100 or more: [ 125, 220, 100 ]

I executed the above example code and added the screenshot below.

Filter Arrays in TypeScript

The orderTotals variable has the type number[], so TypeScript knows that every total inside the callback is a number. The condition total >= 100 returns true for 125, 220, and 100, so filter() adds those values to largeOrders.

The original orderTotals array remains unchanged. This behavior is useful when one part of your dashboard needs all orders while another needs only large orders.

If you need to calculate values after filtering, you can combine this with the array reduce method in TypeScript.

Filter Even or Odd Numbers

You can use the remainder operator (%) to filter numbers by a repeating rule. This is useful when processing batch records, page numbers, IDs, or alternating dashboard rows.

const ticketIds: number[] = [101, 102, 103, 104, 105, 106];

const evenTicketIds: number[] = ticketIds.filter((id) => id % 2 === 0);
const oddTicketIds: number[] = ticketIds.filter((id) => id % 2 !== 0);

console.log("Even ticket IDs:", evenTicketIds);
console.log("Odd ticket IDs:", oddTicketIds);

Sample output:

Even ticket IDs: [ 102, 104, 106 ]
Odd ticket IDs: [ 101, 103, 105 ]

I executed the above example code and added the screenshot below.

How to Filter Arrays in TypeScript

The expression id % 2 === 0 checks whether a number divides evenly by two. TypeScript keeps the result type as number[] because the source array contains numbers.

This approach is much clearer than manually creating an empty array and pushing matching values in a loop. However, loops still help when you need more control over each item. You can learn more in this guide on TypeScript for loops with arrays.

Filter a String Array

String filtering is common in search boxes, tags, email lists, file names, and category selectors. For example, Ethan may want to display only product categories that contain the word “office.”

const productCategories: string[] = [
"Office Chairs",
"Kitchen Supplies",
"Office Desks",
"Outdoor Furniture",
"Office Lamps"
];

const officeCategories: string[] = productCategories.filter((category) =>
category.toLowerCase().includes("office")
);

console.log("Office categories:", officeCategories);

Sample output:

Office categories: [ 'Office Chairs', 'Office Desks', 'Office Lamps' ]

I executed the above example code and added the screenshot below.

Filter Arrays TypeScript

The code converts each category to lowercase before checking it with includes(). This makes the search case-insensitive, so "office", "Office", and "OFFICE" all match.

The includes() method returns a boolean value. When it finds "office" in a category, filter() keeps that category.

For other ways to check text, read how to check if a string contains a substring in TypeScript.

Pro Tip: I always normalize search text with toLowerCase() before filtering user-entered values. Without it, a simple capitalization difference can make a valid result disappear.

Filter an Array of Objects in TypeScript

Real applications usually filter arrays of objects rather than simple strings or numbers. An object array may contain customer records, orders, support tickets, employees, or API response data.

An interface defines the expected shape of an object. It improves type safety, which means TypeScript can catch incorrect property names and invalid values before your code runs.

Filter Objects by One Property

In this example, each order has an ID, customer name, total, and status. We only want completed orders for the sales report.

interface Order {
id: number;
customerName: string;
total: number;
status: "pending" | "completed" | "canceled";
}

const orders: Order[] = [
{ id: 1001, customerName: "Olivia Carter", total: 125, status: "completed" },
{ id: 1002, customerName: "Noah Bennett", total: 89, status: "pending" },
{ id: 1003, customerName: "Emma Walker", total: 220, status: "completed" },
{ id: 1004, customerName: "Liam Cooper", total: 67, status: "canceled" }
];

const completedOrders: Order[] = orders.filter((order) => order.status === "completed");

console.log("Completed orders:", completedOrders);

Sample output:

Completed orders: [
{
id: 1001,
customerName: 'Olivia Carter',
total: 125,
status: 'completed'
},
{
id: 1003,
customerName: 'Emma Walker',
total: 220,
status: 'completed'
}
]

The Order interface ensures every object has the same required fields. It also restricts status to three allowed values: "pending", "completed", and "canceled".

The filter callback checks each order’s status. It keeps only objects with "completed". The result remains an Order[], so you still get autocomplete and type checking when using completedOrders.

For more object-array patterns, see how to filter an array of objects in TypeScript.

Filter Objects by Multiple Conditions

Many business rules need more than one condition. For example, your report may need completed orders worth at least $100.

Use the logical AND operator (&&) when every condition must pass.

interface Order {
id: number;
customerName: string;
total: number;
status: "pending" | "completed" | "canceled";
}

const orders: Order[] = [
{ id: 1001, customerName: "Olivia Carter", total: 125, status: "completed" },
{ id: 1002, customerName: "Noah Bennett", total: 89, status: "pending" },
{ id: 1003, customerName: "Emma Walker", total: 220, status: "completed" },
{ id: 1004, customerName: "Liam Cooper", total: 67, status: "completed" },
{ id: 1005, customerName: "Ava Mitchell", total: 310, status: "canceled" }
];

const highValueCompletedOrders: Order[] = orders.filter(
(order) => order.status === "completed" && order.total >= 100
);

console.log("High-value completed orders:", highValueCompletedOrders);

Sample output:

High-value completed orders: [
{
id: 1001,
customerName: 'Olivia Carter',
total: 125,
status: 'completed'
},
{
id: 1003,
customerName: 'Emma Walker',
total: 220,
status: 'completed'
}
]

The first condition checks whether the order is complete. The second checks whether the order total is at least $100. Because && requires both conditions to return true, the code excludes pending, canceled, and low-value completed orders.

You can use || instead when either condition should keep an item. For example, you might keep orders that are either pending or above $200.

For a deeper example, read how to filter an array of objects by multiple properties in TypeScript.

Filter Objects with a Search Term

A customer search feature often filters object data as someone types. The following code looks for customers whose names contain a search term.

interface Customer {
id: number;
name: string;
city: string;
isActive: boolean;
}

const customers: Customer[] = [
{ id: 1, name: "Sophia Johnson", city: "Seattle", isActive: true },
{ id: 2, name: "Mason Williams", city: "Denver", isActive: true },
{ id: 3, name: "Isabella Johnson", city: "Boston", isActive: false },
{ id: 4, name: "James Brown", city: "Seattle", isActive: true }
];

const searchTerm: string = "johnson";

const matchingCustomers: Customer[] = customers.filter((customer) =>
customer.name.toLowerCase().includes(searchTerm.toLowerCase())
);

console.log("Matching customers:", matchingCustomers);

Sample output:

Matching customers: [
{ id: 1, name: 'Sophia Johnson', city: 'Seattle', isActive: true },
{ id: 3, name: 'Isabella Johnson', city: 'Boston', isActive: false }
]

This code lowercases both values before comparing them. That protects the search from capitalization differences.

In a frontend application, you might run this code after every search-box update. In a backend service, you might filter a small in-memory result set after receiving data from another system. For large database tables, filter in the database query instead of loading everything into memory.

If you need to locate just one record instead of several, use the guide to finding an object in an array by property in TypeScript.

Filter Arrays in TypeScript Without Mutation

A mutation changes an existing value or object directly. Some array methods mutate the original array, but filter() does not.

That makes filter() a safe choice when multiple parts of your application share the same source data.

const allRegions: string[] = ["West", "East", "South", "North"];
const visibleRegions: string[] = allRegions.filter((region) => region !== "East");

console.log("Original regions:", allRegions);
console.log("Visible regions:", visibleRegions);

Sample output:

Original regions: [ 'West', 'East', 'South', 'North' ]
Visible regions: [ 'West', 'South', 'North' ]

The source array still contains "East". The visibleRegions variable points to a separate array created by filter().

This behavior works well in React components, dashboard state, API response transformations, and reporting scripts. You can keep the full dataset while creating smaller views for each user action.

If you need to remove one item and intentionally replace the source value, see how to remove an item from an array in TypeScript.

Filter a Readonly Array in TypeScript

A readonly array is an array that TypeScript prevents you from modifying. It is useful when you want to protect source data from operations such as push(), pop(), sort(), or reverse().

You can still use filter() on a readonly array because filter() returns a new array instead of changing the original one.

const priorityCustomers: readonly string[] = [
"Olivia Carter",
"Noah Bennett",
"Emma Walker",
"Liam Cooper"
];

const customersWithLetterA: string[] = priorityCustomers.filter((customer) =>
customer.toLowerCase().includes("a")
);

console.log("Priority customers:", priorityCustomers);
console.log("Customers containing 'a':", customersWithLetterA);

Sample output:

Priority customers: [ 'Olivia Carter', 'Noah Bennett', 'Emma Walker', 'Liam Cooper' ]
Customers containing 'a': [ 'Olivia Carter', 'Noah Bennett', 'Emma Walker' ]

The priorityCustomers array is protected from direct changes. For example, priorityCustomers.push("Ava Mitchell") would cause a TypeScript error.

However, filter() creates a fresh string[], so customersWithLetterA is a normal mutable array. You can add, remove, or sort values in the filtered result if your application needs that.

Read more about this useful pattern in readonly arrays in TypeScript.

Remove Undefined Values with a Type Guard

API data does not always arrive in a clean format. You may receive an array that includes valid values along with undefined entries. A normal filter condition may clean the data at runtime, but TypeScript may still think undefined values exist.

A type guard is a function that checks a value and tells TypeScript what type remains after the check.

const salesRepresentatives: Array<string | undefined> = [
"Olivia Carter",
undefined,
"Noah Bennett",
undefined,
"Emma Walker"
];

const isDefined = <T>(value: T | undefined): value is T => value !== undefined;

const activeSalesRepresentatives: string[] = salesRepresentatives.filter(isDefined);

console.log("Active sales representatives:", activeSalesRepresentatives);

Sample output:

Active sales representatives: [ 'Olivia Carter', 'Noah Bennett', 'Emma Walker' ]

The salesRepresentatives array has the type Array<string | undefined>. Without a type guard, TypeScript may continue to treat filtered values as possibly undefined.

The reusable isDefined function uses a generic function. A generic is a reusable type definition that works with many data types. Here, <T> means the same function works with string, number, objects, or other values.

The part value is T tells TypeScript that every value returned as true is definitely defined. That gives you a final result with the cleaner string[] type.

This technique is especially useful after handling incomplete API responses. You can also review how to remove undefined values from an array in TypeScript.

Create a Reusable Generic Filter Function

When you repeat the same filtering logic across a Node.js service or frontend project, create a reusable function. This reduces duplicate code and keeps your business rules in one place.

The following generic function filters any object array by an isActive property.

interface HasActiveStatus {
isActive: boolean;
}

interface Customer extends HasActiveStatus {
id: number;
name: string;
city: string;
}

interface Product extends HasActiveStatus {
id: number;
name: string;
price: number;
}

function getActiveItems<T extends HasActiveStatus>(items: readonly T[]): T[] {
return items.filter((item) => item.isActive);
}

const customers: Customer[] = [
{ id: 1, name: "Sophia Johnson", city: "Seattle", isActive: true },
{ id: 2, name: "Mason Williams", city: "Denver", isActive: false }
];

const products: Product[] = [
{ id: 101, name: "Standing Desk", price: 499, isActive: true },
{ id: 102, name: "Desk Lamp", price: 89, isActive: false },
{ id: 103, name: "Office Chair", price: 249, isActive: true }
];

const activeCustomers: Customer[] = getActiveItems(customers);
const activeProducts: Product[] = getActiveItems(products);

console.log("Active customers:", activeCustomers);
console.log("Active products:", activeProducts);

Sample output:

Active customers: [
{ id: 1, name: 'Sophia Johnson', city: 'Seattle', isActive: true }
]
Active products: [
{ id: 101, name: 'Standing Desk', price: 499, isActive: true },
{ id: 103, name: 'Office Chair', price: 249, isActive: true }
]

The HasActiveStatus interface defines the one property every supported item must have. The generic type T extends HasActiveStatus means T can be any object type as long as it includes isActive: boolean.

This design lets one function filter customers, products, tickets, users, or subscriptions. The input accepts readonly T[], so it works with both normal arrays and readonly arrays. The function returns a new T[] and never changes the source.

You can learn more reusable typing patterns in this guide on TypeScript generic anonymous functions.

Combine filter() with map() and reduce()

In real reporting code, filtering is often only the first step. You may filter valid records, map them into display values, and reduce them into a total.

For example, Ethan wants the names and total revenue from completed orders worth at least $100.

interface Order {
id: number;
customerName: string;
total: number;
status: "pending" | "completed" | "canceled";
}

const orders: Order[] = [
{ id: 1001, customerName: "Olivia Carter", total: 125, status: "completed" },
{ id: 1002, customerName: "Noah Bennett", total: 89, status: "pending" },
{ id: 1003, customerName: "Emma Walker", total: 220, status: "completed" },
{ id: 1004, customerName: "Liam Cooper", total: 67, status: "completed" }
];

const qualifiedOrders: Order[] = orders.filter(
(order) => order.status === "completed" && order.total >= 100
);

const customerNames: string[] = qualifiedOrders.map((order) => order.customerName);

const qualifiedRevenue: number = qualifiedOrders.reduce(
(total, order) => total + order.total,
0
);

console.log("Qualified customers:", customerNames);
console.log("Qualified revenue:", qualifiedRevenue);

Sample output:

Qualified customers: [ 'Olivia Carter', 'Emma Walker' ]
Qualified revenue: 345

First, filter() keeps only qualifying order objects. Next, map() creates a new string array containing customer names. Finally, reduce() adds each matching order total into one revenue number.

Each method returns a new result and leaves orders unchanged. This pipeline is clean for small and medium datasets because each stage has one clear job.

For very large arrays, avoid chaining several methods when performance matters. A single for...of loop may reduce temporary arrays and memory use. Still, I usually start with readable filter(), map(), and reduce() code unless profiling shows a real bottleneck.

Things to Keep in Mind

  • filter() returns a new array: The original array remains unchanged, which makes filter() safer than methods that mutate the source.
  • Use explicit array types: Declare values as string[], number[], or an interface array such as Order[] to improve type safety and editor autocomplete.
  • Return a boolean condition: Your filter callback should clearly return true to keep an item and false to exclude it.
  • Normalize user search text: Use toLowerCase() before comparing strings when search results should ignore capitalization.
  • Use type guards for missing data: Filter undefined or null values with a type guard when you need TypeScript to narrow the final type.
  • Avoid repeated filtering on large data: Filter once, store the result, and reuse it when your script processes thousands of records.

Frequently Asked Questions

How do I filter an array in TypeScript?

Use the filter() method with a callback that returns true for values you want to keep. For example, numbers.filter((number) => number > 10) returns a new array containing only numbers greater than 10. The original array stays unchanged.

Does filter() mutate an array in TypeScript?

No, filter() does not mutate the original array. It creates and returns a new array with matching values. This makes it a good choice when several parts of your application use the same source data.

How do I filter an array of objects in TypeScript?

Create an interface for the object shape, then check an object property inside filter(). For example, orders.filter((order) => order.status === "completed") returns only completed orders. TypeScript preserves the Order[] type in the result.

How do I filter undefined values from an array in TypeScript?

Use a type guard such as const isDefined = <T>(value: T | undefined): value is T => value !== undefined;. Then call values.filter(isDefined). This removes undefined values and tells TypeScript that the result contains only valid values.

Can I filter a readonly array in TypeScript?

Yes, you can call filter() on a readonly array because it does not modify the source. The method returns a new normal array containing the matching values. You cannot use modifying methods such as push() on the original readonly array.

What is the difference between filter() and find() in TypeScript?

filter() returns an array containing every matching item. find() returns only the first matching item or undefined if no match exists. Use filter() for lists and find() when you need one record.

Filtering arrays in TypeScript gives you a clean way to prepare API data, build search experiences, and create focused dashboard reports without changing the original data. Start with filter() for simple conditions, use interfaces for object arrays, and add type guards when external data may include missing values.

For most projects, filter() with well-defined TypeScript types is the clearest and safest approach. I hope you found this article helpful.

You May Also Like

51 Python Programs

51 PYTHON PROGRAMS PDF FREE

Download a FREE PDF (112 Pages) Containing 51 Useful Python Programs.

pyython developer roadmap

Aspiring to be a Python developer?

Download a FREE PDF on how to become a Python developer.

Let’s be friends

Be the first to know about sales and special discounts.