Crafting a Generic Search Function
Explore how to create a generic search function using TypeScript and React. Learn to write a type-safe function that filters objects by string or number properties and understand how to integrate it into your app for dynamic search capabilities.
Now that our application successfully displays our widgets and people objects, we can start building our first functionality, a generic search function that we’ll call genericSearch.
What is search, really?
In its most abstract form, searching is finding data that matches a query. In our situation, because we have already decided to map over both the widgets and people variables, we could consider our search to just be the call to the JavaScript array filter function before we call map to render the items. With our current setup, that looks something like this:
Our genericSearch function will accept the object itself, as well as some sort of query to use to actually filter for the values.
Writing the genericSearch function
Let’s start writing our genericSearch function. First, we need to create a new folder called utils and then a new file genericSearch.ts. We can start by writing the signature of the function.
We know that the function will be generic since it will be able to sort objects of any type. So, we can go ahead and add the <T> and the object, which is of type T.
Why are we using the
export const genericSearchsyntax instead ofexport default function genericSearch? Typically the recommendation is to useexport constoverexport defaultsinceexport constis slightly more flexible thanexport default. We can rename variables that are imported fromexport constmodules, whereas we can’t withexport default.
Our query will be text-based, so we can add that with type string:
Since this function is called within the filter call, we know it must satisfy the criteria to be a true or falseboolean:
What should we filter with?
The signature of genericSearch is still incomplete. We can’t compare a query of type string to an object of type T, at least not without accessing a property of that object. We’ll be using the TypeScript operator keyof to accept a parameter that can tell us which property to compare to query. We’ll call this parameter property:
Writing the body of genericSearch
Now that we know that we’ll be searching with property, we’ll get that value from our object.
TypeScript won’t give us an error because property quite literally is a keyof T. Now, we can attempt to use our query value and see if the query is included in the value.
This time, TypeScript gives us an error because it doesn’t know for sure that that value is of type string. In JavaScript, object properties can point to all sorts of things. They can point to both primitive types, like Boolean, Null, Undefined, Number, BigInt, String, and Symbol, or they can point to another nested object entirely!
For now, we’ll focus on the properties which are indeed of type string. To enforce this, we’ll use a type guard before calling includes. If this type guard fails, we simply return false since it’s a value type that our function doesn’t handle yet.
Small improvement to accept numbers
With some creative thinking, we can also allow properties of type number to work with this filter function. We can add number to our type guard, and then, make use of JavaScript’s toString() function to convert it to a string.
(If the type of value is already string, this is fine, the value will remain as type string.)
Using genericSearch
Now, when we go back in App.tsx, we can actually import and use our new genericSearch function. Since we’re already rendering the titles of the widgets, let’s apply genericSearch to the property title.
Granted, we have no way of changing query right now, but we will see how to wire that up in the coming lessons.
We’ve written an initial genericSearch function that is able to search any properties which yield a type string for any object of type T. However, we’re currently limited to one property, which is a disadvantage. What if we want to search with both the title and description of the widgets objects simultaneously? For example, in the case of the people variable, what if we would like to search with both the firstName and lastName?
That functionality isn’t possible with our current implementation of genericSearch. In the next lesson, we’ll see how we can improve genericSearch to look through multiple properties simultaneously.