TypeScript/JavaScript Filter array of objects by property value

eye-catch JavaScript/TypeScript

An array often needs to be filtered by a condition. That can easily be done filter function that is implemented in Array object.

Let’s see how to filter an array in JavaScript/TypeScript.

Sponsored links

Syntax

The syntax is simple. filter function requires a callback. The callback must return boolean.

array.filter(callback);

The callback can directly be defined in it by using an arrow function as known as a lambda function. If the logic can be written in a single line, return keyword can be excluded.

array.filter((element) => true);

If multiple lines are needed, write the code in the brackets.

array.filter((element) => {
    // do something with element here
    // return true or false at the end
    return true;
});

Check the following post if you are not familiar with an arrow function.

Sponsored links

Filter number array

Let’s check the actual usage. In this example, it filters number that is bigger than 10.

const numArray = [5, 1, 78, 2, 42, 4, 11, 4];
console.log(numArray.filter((x) => x > 10)); // [ 78, 42, 11 ]

As you can see above, numbers are filtered as expected.

If we need to filter discontinuous numbers, we can define them in the following way.

console.log(numArray.filter((x) => x === 78 || x === 42 || x === 11)); // [ 78, 42, 11 ]
console.log(numArray.filter((x) => [78, 42, 11].includes(x))); // [ 78, 42, 11 ]

Both of them result in the same. The first one is simpler but it can be much longer if there are lots of elements needed. The second way is shorter and easy to read. The advantage of the second way is that the filtering condition/list can be defined separately. It makes the code more readable.

If we want to know only whether the array contains those values or not, use some function instead. It returns a boolean instead of the array.

console.log(numArray.some((x) => [78, 42, 11].includes(x))) // true

Filter string array

How can we filter string array? It’s basically the same. Just compare the value with the element.

const strArray = ["aa", "bb", "aabb", "aa", "cc", "aacc"];
console.log(strArray.filter((x) => x == "aa")); // [ 'aa', 'aa' ]

If we need strings that contain something, use includes method or a regex.

console.log(strArray.filter((x) => x.includes("aa")));  // [ 'aa', 'aabb', 'aa', 'aacc' ]
console.log(strArray.filter((x) => /aa.*/.test(x)));    // [ 'aa', 'aabb', 'aa', 'aacc' ]

Filter array of objects by property value

We learned how to filter number/string array but how can we filter for object array? Okay, let’s dig into it further. Assume that we have the following class.

class Product {
    constructor(
        public id: number,
        public name: string,
    ) { }
}

const objArray: Product[] = [
    new Product(100, "water"),
    new Product(101, "apple juice"),
    new Product(102, "banana juice"),
    new Product(200, "banana"),
    new Product(201, "apple"),
];

Once we know the data type in the callback, we can easily access the desired property.

console.log(objArray.filter((item) => item.id >= 100 && item.id < 200));
// [
//   Product { id: 100, name: 'water' },
//   Product { id: 101, name: 'apple juice' },
//   Product { id: 102, name: 'banana juice' }
// ]
console.log(objArray.filter((item) => item.name.includes("banana")));
// [
//   Product { id: 102, name: 'banana juice' },
//   Product { id: 200, name: 'banana' }
// ]

That’s easy.

Filter mixed data type array

In some cases, there are multiple types in an array. Imagine that we define an interface or base class that some other classes implement/extend it. In this case, an array has mixed data types in it.

I defined the following two classes and use them in an array.

class PcProduct extends Product {
    constructor(
        id: number,
        name: string,
        public ram: string,
        public cpu: string,
    ) {
        super(id, name);
    }
}
class AlcoholProduct extends Product {
    constructor(
        id: number,
        name: string,
        public type: string,
    ) {
        super(id, name);
    }
}

const mixedArray = [
    new PcProduct(100, "laptop-pc-A", "8GB", "2.4GHz"),
    new PcProduct(101, "laptop-pc-B", "16GB", "2.4GHz"),
    new PcProduct(102, "desktop-pc-A", "32GB", "3.0GHz"),
    new AlcoholProduct(301, "Weis Beer", "Beer"),
    new AlcoholProduct(302, "Bombay Sapphire", "Gin"),
    new AlcoholProduct(303, "Glenfarclas", "Whiskey"),
    new AlcoholProduct(304, "Tanqueray", "Gin"),
];

Let’s extract alcohol products from the array. We can simply filter them by comparing id > 300 but we will implement it in a different way.

We can simply compare the data type by using instanceof. Another way is to check whether the object has the property name that is used in one of the classes.

console.log(mixedArray.filter((x) => x instanceof AlcoholProduct))
// [
//   AlcoholProduct { id: 301, name: 'Weis Beer', type: 'Beer' },
//   AlcoholProduct { id: 302, name: 'Bombay Sapphire', type: 'Gin' },
//   AlcoholProduct { id: 303, name: 'Glenfarclas', type: 'Whiskey' }
// ]
console.log(mixedArray.filter((x) => x.hasOwnProperty("type")))
// [
//   AlcoholProduct { id: 301, name: 'Weis Beer', type: 'Beer' },
//   AlcoholProduct { id: 302, name: 'Bombay Sapphire', type: 'Gin' },
//   AlcoholProduct { id: 303, name: 'Glenfarclas', type: 'Whiskey' }
// ]

In our case, type is defined only in AlcoholProduct class. If another class has the same property, this way can’t be applied. Note that the IntelliSense doesn’t recognize the data type if we use hasOwnProperty.

If it’s not a class but interface, we can’t use instanceof keyword. In this case, we should define User-Defined Type Guards as explained in the following post.

We know how to filter the target class now. Next, let’s filter Gin product from it.

We will compare the class first to let IntelliSense know the data type. Then, it can show type property. Return false if the product is not AlcoholProduct.

console.log(mixedArray.filter((x) => {
    if ((x instanceof AlcoholProduct)) {
        return x.type === "Gin";
    }
    return false;
}));
// [
//   AlcoholProduct { id: 302, name: 'Bombay Sapphire', type: 'Gin' },
//   AlcoholProduct { id: 304, name: 'Tanqueray', type: 'Gin' }
// ]

This can be written in one-liner.

console.log(mixedArray.filter((x) => x instanceof AlcoholProduct && x.type === "Gin"));

The result is of course the same as the previous one.

Comments

Copied title and URL