Using Array.filter() method in TypeScript

Updated: January 8, 2024 By: Guest Contributor Post a comment

Introduction

TypeScript, a superset of JavaScript, offers all of JavaScript’s features with the added bonus of type safety. Among its array manipulation tools, the filter() method stands out for its utility. This tutorial will steer you through the use of Array.filter() with practical TypeScript examples.

Understanding filter()

The filter() method in TypeScript creates a new array that includes all elements of the calling array that meet a certain condition set by the provided function. Signature of filter() in TypeScript:

array.filter(callback(element[, index[, array]])[, thisArg])

Here callback is the function that tests each element (optionally you can access the element’s index and the whole array), and thisArg is an optional parameter that sets this for the callback function.

Basic Example

Let’s start with a simple example where we use filter() to find all even numbers in an array:

const numbers: number[] = [1, 2, 3, 4, 5];
const evenNumbers = numbers.filter(number => number % 2 === 0);
console.log(evenNumbers); // Output: [2, 4]

Using Type Annotations with filter()

In TypeScript, using type annotations ensures that the filter() method is applied to arrays with elements of the correct type:

const fruits: string[] = ['apple', 'banana', 'cherry', 'date'];
const fruitsWithA = fruits.filter((fruit: string) => fruit.toLocaleLowerCase().includes('a'));
console.log(fruitsWithA); // Output: ['apple', 'banana', 'date']

Type annotations help maintain the array’s integrity, ensuring no unintended types are introduced during the filter operation.

Filtering with Interfaces

When dealing with complex types, such as objects, interfaces can be of great help to enforce a structure:

interface Animal {
    name: string;
    species: string;
}
const zoo: Animal[] = [
    { name: 'Leo', species: 'lion' },
    { name: 'Marty', species: 'zebra' },
    { name: 'Melman', species: 'giraffe' },
    { name: 'Gloria', species: 'hippopotamus' }
];
const lions = zoo.filter((animal: Animal) => animal.species === 'lion');
console.log(lions); // Output: [{ name: 'Leo', species: 'lion' }]

Advanced Filtering

Advanced usage of the filter() method can include filtering based on the comparison of multiple fields or nested object properties:

Here is an advanced example where we filter a list of movies by genre and year:

interface Movie {
    title: string;
    genre: string;
    year: number;
}
const movies: Movie[] = [
    { title: 'Inception', genre: 'Sci-Fi', year: 2010 },
    { title: 'The Godfather', genre: 'Crime', year: 1972 },
    { title: 'The Shawshank Redemption', genre: 'Drama', year: 1994 },
    { title: 'Parasite', genre: 'Drama', year: 2019 }
];
const classicDramas = movies.filter((movie: Movie) => movie.genre === 'Drama' && movie.year < 2000);
console.log(classicDramas); // Output: [{ title: 'The Shawshank Redemption', genre: 'Drama', year: 1994 }]

This finds all drama movies released before the year 2000.

Generics and filter()

TypeScript’s generics enhance the functionality of methods like filter() by providing a way to create reusable components.

For instance, here is how you could create a generic filter function:

function filterArray<T>(array: T[], predicate: (element: T) => boolean): T[] {
    return array.filter(predicate);
}
const numbers: number[] = [1, 2, 3, 4, 5];
const even = filterArray(numbers, (n) => n % 2 === 0);
console.log(even); // Output: [2, 4]

The filterArray function can now be used with arrays of any type.

Chaining filter() with Other Methods

Chaining filter() with other array methods can lead to concise and powerful operations. Here’s an example of chaining filter with map():

const numbers: number[] = [1, 2, 3, 4, 5];
const doubledEvens = numbers.filter(n => n % 2 === 0).map(n => n * 2);
console.log(doubledEvens); // Output: [4, 8]

Filtering with Type Guards

In TypeScript, using type guards in your filter callbacks can provide additional type safety:

type StringOrNumber = string | number;
const items: StringOrNumber[] = [1, 'two', 3, 'four'];
function isString(item: StringOrNumber): item is string {
    return typeof item === 'string';
}
const strings = items.filter(isString);
console.log(strings); // Output: ['two', 'four']

This guarantees that the resulting ‘strings’ array will only contain string types.

Conclusion

Throughout this tutorial, we’ve covered the versatility and power of TypeScript’s filter() method. Be it simple filtering of primitive data or advanced operation on complex types, filter() becomes indispensable in creating TypeScript applications with robust and maintainable code.