Advanced TypeScript: Generic Search, Sorting, and Filtering | Chris Frewin | Skillshare

Playback Speed


  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x

Advanced TypeScript: Generic Search, Sorting, and Filtering

teacher avatar Chris Frewin, Full Stack Software Engineer

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

19 Lessons (3h 18m)
    • 1. Introduction and Course Overview

      3:12
    • 2. Environment Setup

      2:44
    • 3. A First Look on How to Use Generics in TypeScript

      11:18
    • 4. Additional Generics in TypeScript Example

      5:48
    • 5. Creating Mock Data for the Application

      7:18
    • 6. Crafting a Generic Search Function in TypeScript

      12:35
    • 7. Creating a Search Input for Our Generic Search Function

      6:17
    • 8. Adding a useDebounce React Hook to Reduce Search onChange Event Load

      5:50
    • 9. Crafting a Generic Sort Function in TypeScript

      4:39
    • 10. Creating a Generic Sort React Component

      12:22
    • 11. Improving the Application's UI - Bootsrap and react-moment

      19:32
    • 12. Adding Ascending and Descending Functionality to Our Sorter Component

      11:13
    • 13. Crafting a Generic Filter Function in TypeScript

      10:28
    • 14. Building a Generic React Component for our Generic Filter Function

      14:05
    • 15. Adding Falsey Functionality to the Generic Filter React Component

      18:23
    • 16. Render Props, or Children as a Function in React

      15:51
    • 17. Creating a Single Generic Component to Unite Search, Sort, and Filter

      31:48
    • 18. BONUS: Using the Extract TypeScript Keyword to Improve our Generic Sort Function

      3:21
    • 19. Course Review and Final Comments

      1:44
  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels
  • Beg/Int level
  • Int/Adv level

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

68

Students

--

Projects

About This Class

This course is going to be all about using generics in TypeScript! In this course, we'll start off by going over some examples of what generics are in TypeScript and when they can be used to our advantage.

We'll learn and see how to create generic search, sort, and filter functions that can be applied to any type of data we throw at them. To give the generic functions life, we'll use a simple React UI with made-up 'Widget' and 'Person' data types.

As with all my other courses, through each lesson of the course, I make commits to a git repository, which you can access lesson by lesson and see the application run on your own machine. The repository is on GitHub:

https://github.com/princefishthrower/react-typescript-course-generic-search-sort-filter

and a copy of the final branch of the application we'll make is on GitHub pages:

https://princefishthrower.github.io/react-typescript-course-generic-search-sort-filter/

Generics are a fairly advanced aspect of TypeScript, and this course will not be going over more of the basics. If you'd be interested in a TypeScript overview course, please let me know; I think that's something I could put together. Otherwise, I think there are plenty of other great TypeScript tutorials out on the web, and I'll link to some of the ones I've used myself in the class resources - the TypeScript Deep Dive.txt

I put a lot of time and effort into this course to show you the power of generics, and how to use them throughout your applications. I hope you enjoy this course!

Meet Your Teacher

Teacher Profile Image

Chris Frewin

Full Stack Software Engineer

Teacher

Hi everyone!

I've been a professional full stack software engineer for 7+ years, and I've been programming for many more. In 2014, I earned two separate degrees from Clarkson University: Mechanical Engineering and Physics. I continued at Cornell for my M.S. Degree in Mechanical Engineering. My thesis at Cornell was a technical software project where I first learned Bash and used a unique stack of Perl and Fortran, producing a publication in the scientific journal Combustion and Flame: "A novel atom tracking algorithm for the analysis of complex chemical kinetic networks".

After opening up my first terminal while at Cornell, I fell in love with software engineering and have since learned a variety of frameworks, databases, languages, and design patterns, including TypeScrip... See full profile

Class Ratings

Expectations Met?
  • Exceeded!
    0%
  • Yes
    0%
  • Somewhat
    0%
  • Not really
    0%
Reviews Archive

In October 2018, we updated our review system to improve the way we collect feedback. Below are the reviews written before that update.

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Introduction and Course Overview: Hi everyone. This course is going to be all about using generics in type script. Now, what exactly are generics? Well, we already know it's usually a good idea when we write software to make our code reusable and more flexible. But in a strictly typed language like Type Script, there's also a way to make our typings more reusable and more flexible. And that is when generics. So in this course we're going to go through three key functionalities. A generic search, a generic sort, and a generic filter. And we're also going to see how we can use generics to create generic components in React, where the typing will be looked at. And we'll be able to generate UI components just from the types alone. So this course was a lot of fun for me to record. And even during some lessons, I was surprised at the power of Type Script and its intelligence in the editor. So I hope you'll join me on this course and hope you have a lot of fun. In lesson two, we scaffold our project defining the node and NPM versions we will use and using Create React app to bootstrap our application. In lessons 34, I showed basic examples of what generics look like in type script and when to use them and what benefits they provide. In lesson five, we setup mock data for our application with two different types, which we'll use throughout the course. And lesson 678, we build out our generic search, writing the function itself a UI component for it, as well as a fun optimization. In Lessons 910, we continue on with generic sorting and a UI component bore. And less than 11, we take a step back and add some Bootstrap styling to our app to make it more tests friendly. In less than 12, we returned to finish up the generic sorting and lessons 131415, we build out our final main functionality, generic filtering. In less than 16, I show a neat feature of React, which is rendered products. We can have our children be a function. In Lesson 17, we pull everything together and organize all our generic functionality into one, orchestrating generic components. In less than 18, I show how to use type scripts, extract keyword as one final optimization to the generic sort function we wrote. And less than 19 is the conclusion and course review. I also want to mention that this course is geared more towards intermediate to advanced type script developers. Generics are a pretty advanced component of the type script language. And I don't go over the basics of type script, like what an interface is or what an enum is, and how to do that in n-type scripts into x. I do spend two lessons at the beginning of the course on a few basic examples, generics. But that's just a warm up to get started. And not as complex as what we'll get into later in the course. And like always, in all my courses, for each lesson, I have a GitHub branch of the code that we did for that lesson. So I hope to see you guys in the next lesson. And if you decide to take the course, I hope you had a lot of fun. So hope to see you there guys ticker. 2. Environment Setup: We'll start off by defining our environment. I'm going to use node version 14 because as of when this course was recorded in January 2021, that was the latest LTS or long-term release and it'll be the active LTS until October 2021. So we'll use version 14 throughout the course. And I usually use nvm for this and we can list our versions. So I have 14.13.1. And if you want to alias that as your default, you can do nvm alias default 14.13.1 if you've installed it. And every time you open a terminal, that will be the default that nvm picks for you. So I've also gone ahead and created already a lesson to branch or the repository. And we can get started bootstrapping the application with Create React app. So that's and we want the template type script. And we want that here. So we just say dot. And we'll let that run. That's done. We can open up Visual Studio code. And the first thing we wanna do here is go through and remove all the extra fluff that we don't need the CSS testing. Anything else we don't need to check that we didn't break anything. You can fire up the app and it looks like it's okay. Check console, nothing. Ok. So we're all set. I'm also going to add the packages Bootstrap and node Sass. Since later in the course we'll be doing some simple custom styling for the application. So we'll install those and node Sass. Great. So in this lesson we've selected to use the latest node LTS, using MDM and bootstrap the application with Create React app. Now that we have a sort of app playground at work with. In the next lesson, I'll give a brief overview of what generics are in type script and how we can actually use them to our benefit. 3. A First Look on How to Use Generics in TypeScript: So in the last lesson, we created the beginnings of our app with Create React app, I'll now go over exactly what generics are and how we can use them in type script. I'm first going to create a folder called generics under source and just a file called generic stuff DES as an example. So in React, we often hear that it's important to design components that are reusable, whether by keeping components small or composing them in a nice way. Or for example, using prompts to plot any parts that can be modified for any use case. But the same is true for functions and classes that we build alongside or outside of our React components. In this course, we'll be building search, sorting and filtering functionality. And if you've ever built a large application, you often use these types of functionalities all across the app on multiple pages areas, and most importantly for a variety of different datatypes. So my first simple example is actually going to be a little preview of what we'll see in lesson five, but a bit more simplified. So I'm just going to start with an interface called i fu bar, okay? And that is a type that just has properties foo, which is a string in bar, which is a string. And just to add some concrete values to what that type could look like. We'll define an array called toolbars. And I'll put in some values here. So let's imagine for some reason that somewhere in our app, we would want to sort a datatype like this. We get from an API, a list of few bars, and we wanna sort them and say we want to sort them on the 2k property. So we can imagine writing a sort function. And we'll just call it sorted by f2, where we pass in some fu bars. They're the same type. And we'll call the sort function, the built in JavaScript function on this array. So we have to write this comparator function. And we can just use the simple string comparison. So if a dot foo is greater than beta X2, turn one. If a dot foo is less than b dot f2. And negative one. Otherwise, we'll return 0 indicates they'd be equal. Then you can imagine kind of the same pattern to sort by the other property bar would be sort by bar. And it ultimately require changing all these two bar. And now that would actually work just fine if we were only concerned with sorting a type like this. But we can imagine a much more complex type where we have dozens of properties or even nested properties. And so we can't go around all day writing an explicit sort function with an explicit key value that would take forever and would be repetitive code. So this is a perfect use case for generics. We can create a generic function that will replace both these two functions but also be extendable. For example, if we had a more complex type later with something like hello. We'd also be able to sort on hello or any other type of property that could come into the type. So let's write that. And now the first step with generics or to signify the type script that it's a generic function, is to start with angle brackets and a capital letter. Now, there's various conventions for exactly what this capital letter is. It's usually a single letter and sometimes it starts with t. But you can see other conventions as well. And if you need more generic types, you would continue as T, u, v, and so on with this type of convention. If you already have a little bit of experience with reactant type script, you may have noticed when you create a class, an example component, which extends the react component type. You look in this type. We see also the same convention with these angle brackets. And in this case they've chosen a different convention. The P is for props, S means state, and SS is for snapshot, but that's rarely used. But the point is that these props and states are also generic types. We know that React can use prompts and states in its components. But react doesn't care what shape or what type these two types are. And so this notation here really just means, I'm expecting a type. I don't care what it is. And I'm going to write the logic in my class or function according to these generic types. So we'll get back to our sorted by key function. And now we've signified this generic type t, and we can use that in the rest of our signature of the function. So similar to these other functions, we won't have array of i fu bar, but will now have array of this generic type t. And I won't call it foo bars anymore either because it's generic. So I'll simply just call it data. And that will be an array of t. And now the extension will need to make, instead of explicitly defining the property name such as bar or foo, we're going to use another powerful type script feature by defining a key and using P of T. And this tells type script whatever type we pass as t. This key parameter in this function has to be a T of t. So I'll show an example of how that works exactly in a bit. But let's finish the body of our function. So now we can tall Datastore just as we did above. Still with the AB. And the comparator now is a sub n, b sub d. And even though there is no explicit typing here, because of this qi of t syntax and the way type script works, it knows that we can safely access these objects with this key value because QI is a qi of ti. Finish that'll return 0. So now, how do we actually use this function? When we actually call it, we can't pass a t at execution time. Type script really does need a type. So in our case, if we wanted the same functionality as sorted by f2, we would call sort by key and pass the specific type that we're interested in sorting. And in this case our data is this full bars array. And the key that we want to sort if we're looking to reproduce this functionality is f2. And we can pass that as a string. And this lines all good. We don't see any errors or fuzzy lines. So type scripts, happy to do that for us. Now as I mentioned, this qi of t functionality is very powerful. So if you have a very complex type here, it's easy to remember we have only foo and bar as our keys, but we have a very big type. Perhaps you forgotten or don't remember the key name. And we were to write sort by t bar, foobar type. And just anything like that. We'll see here that Type Script complaints and says argument of type cap is not assignable to parameter of type key foo bar. So you can look into foobar Satan, why is that? Okay, we only have these properties, foo and bar. There is no cat property. But if there was, we would see that warning would go away. So just in this initial example, we can already see the power of generics where, for example, this sort function has replaced and nearly endless amount of explicit sort functions that we would otherwise have to write by hand. So in this example, we've seen how generics can help us create flexible and reusable code. But we can also use generics to help guide our typings and not make mistakes with typings. 4. Additional Generics in TypeScript Example: So in the last lesson, we saw how generics and type script can save us from rewriting a lot of code. And we wrote a flexible sort function which can accept any type and then sort on any property in that type with qi of t. But in addition or their uses in creating flexible and reusable code. Generics can also protect us from making mistakes with types that certain functions or classes expect. And so for this example, I'm going to create a few classes here. Will make an animal class, which has a leg count and that's a number. And then two other classes do cat, which extend. Animal that has four legs, and Kangaroo that has two legs. Then which we'll need for illustration later. I'm gonna make a bacteria class which doesn't extend animal. And we can leave that empty for now. So these various classes, let's imagine that we want to print out the legs. And we don't want to write a cat printer for the leg count and a kangaroo leg printer, we wanna just write one function that can print the legs of an animal. So how can we do that? Again, we can use generics. So we will write a function print layout. And in this case, just prescribing t isn't good enough. Because we know in this function that it has something to do with animal. We wanna print the leg count and we know that all animals have a likeCount. So in this case, we can use the extends keyword. That is, type script will accept any type as long as the given type extends Animal. And of course, we can use that in our signature. And the body would simply be what gap. And so again, similar to our generic function above, will be able to call print lead count. For example, if we creates a cat and we can create a kangaroo. And we can call print lead count for my cat. And we can call it for my cane grew. And we can try to do that with the bacteria. And we see type script is already complaining. And an argument of type bacteria is not assignable to parameter of type animal. And so that's clear. Bacteria does not extend animal and therefore does not meet this generic constraint. And this function won't work. Bacteria anyway, don't have any legs. Makes sense. And so we're all set. And so this function works as we expect and how he designed. So in the last two lessons, we took an initial look into the power of generics and type script, where they enable us to write both reusable code, but also code that is properly typed according to what certain parts of our code are going to do. So just a quick note. This code will be in both lessons, 34 in those branches in the repository. But note that it's just a plain type script file and we're not using it anywhere else in the application. So you'll be able to check these functions out and explore a little bit the errors in the Visual Studio Code IntelliSense by yourself. But in the next lesson, you won't see it anymore and I'll be removing it. Great. In the next lesson, we're finally gonna start adding some mock data to the application. Type that data and move towards a real applicable use case for Type Script generics. 5. Creating Mock Data for the Application: In the last two lessons, we were working with rather basic types and classes for the generic examples. Throughout the rest of the course, we're going to use more complex types to fully illustrate the power of generics. The first type we're going to establish is I widget. So we're going to create a folder called Interfaces and create the file I widget. Yes. And our widgets gonna look like the following. I'm going to paste that in. And we're also going to create a person interface. So paste that in. So the widget we have title, description, ID, which is the number of rating created, updated and is special card, which we'll see that's, there'll be a bit of fun later. The person is a bit simpler, but firstName, lastName, birthday and eye color. And so we want to mock some data for both of these types. So I'm going to create another folder called mock data. We'll do the widgets first. And we'll have it as an array of widget. So I'm gonna paste that in here and export it. Say that. Now I had this from a previous project, but or the people. I was having a hard time thinking of names. So there's a neat tool you can use, which I use quite a lot to mock data. And that is JSON Generator.com. So JSON dash generator.com. And you're actually writing kind of a, a pseudo JavaScript type template language. And those, you can find all the different types here. So you can do, you can do integers and Boolean and even GUID is, and there's other built-in functions like Countries and gender first-name, its all there. So I've defined according to our Type, got the firstName, lastName, birthday and eye color. And you can basically generate as much as you want. So I've generated only ten. Boost that up to 20 more data. We can just copy this. And in our people, same as with widgets. I person. We can fix that. Let's see if this will work. Format that. So now let's render both the people and widgets data. So we can import. And again, type script is already working for us and that we've typed them in here. And those types will carry through wherever we import them. So I'm gonna get rid of this from the boilerplate. And we're just going to map. Let's just do a simple h3 for now. What do we add? Widget. Widget, just the title for now. And the same for people. You can do. Person first-name. Its not giving me the intellisense yet because I haven't imported it. Great. You can start that up. Okay, so it looks like everything is wired properly. So in this lesson we define two types. And I widget interface and an AI person interface. And we created some mock data to add some concrete values to those types. We then imported them. And we made a basic rendering of a few of their properties just to make sure that everything was wired up correctly. So in the next lesson, we will finally get started in writing a reusable generic search function that will apply both to the widgets and the people data. 6. Crafting a Generic Search Function in TypeScript: In the last lesson, we created two types and data for those types. And in our application, we're just mapping over each of our types and rendering a property of those types. So let's build a generic search function for our types. In lesson three, we did a simple sort function. But as it turns out, the generic search function is going to be one of the easiest functions to implement. So we'll start with that. And just start thinking about what a search function really is. And how we can manipulate an array of data with a search. And really what searching is is nothing more than filtering based on a query value. So we can think about filtering our widgets and our people array by putting a filter call before the Map function. So will be filtering according to certain criteria and then mapping the results of what's left. And so in the filter function, we know we'll have our widget. And we can pass that right away to what we'll call generic search. And as I mentioned, we'll need some sort of query to compare it to. So we'll do that. And to create the generic search, I don't want to create the function directly in this component, since it is generic and it'll be reused in other parts of the F, perhaps. So we're going to create a new folder called utils. And we'll create generic search dot ts. So just the normal type script file and will export that as our default function. And again, since this is a generic function, we want to start with those angle brackets and we'll stick with the convention of capital T. And so we know in our application from the filter call, the first parameter will be not widget in this case, but the object of t itself. And we've also decided to pass a query for now, which is not the fine. I'll just make that an empty query for now. And a query which is a string. There is an additional issue here that we have our object and we have the query, but we have nothing to filter it on. And with this filter function, we want the predicate to return either true if it matches our query or false. So we can add that return type. And typed scripts already complaining because I haven't returned anything yet. Then there's still one more thing missing. What exactly are we going to query on? And so similar to what we saw in lesson three with our disorder, we're also going to define a property perimeter, which is again going to use that qi of t. And we should add that to our app. So for now since we're just listing the title, I'm going to also use title as our property to search on. So the first thing we'll do is strip off the value from the object. So the value will be objects of property. And Type Script knows this is ok. Property is a qi of ti, object is type T. So this is valid. And essentially we want to return value is a string. And it's that includes the query. Now already we're running into an issue because type script is so smart. We know that an object can have a variety of properties. And just because we've accessed it here, value isn't necessarily something that can be converted to string here. So we have to build a type guard. So if it's a string and we also know we can use to string on numbers. So add that as well. And this includes, sorry. And then we're missing the default case. So for example, if this value is a function or something else, we're just going to return false as the default. That looks okay. And we just need to import that here. But this isn't really a complete solution. For now. We're searching on title, but it would probably be nice to be able to search on both the title and description. And for the person. Perhaps we'd want a search on the firstName, the lastName, and Eichler. So we should extend the generic search function to accept an array of values or keys of the object that we want to search through. So I'm gonna do that now in the app. And it will hop into generic search to handle that functionality. So I'm going to re-factor this property. And call it properties. And we'll make it an array of qi of ti. And essentially we can keep this same logic, but now we have to do it for every property. So I'm going to map over those properties. And we will apply. We need to store those values. I'll just call them expressions. And so type script, it tells us what this is and we can expect kind of what it is. It's an array of Boolean values. And in the case here for a match, we want to return true if just one of the keys has evaluated to true, that is, if only one of the keys, one or more of the keys matches the current query that we're considering. And so there's another useful built-in array function which we can use. And that is some, not some as an addition, but some as in the determiner. And that is simply returning the expression. So this will evaluate to true. If at least one expression in this array of expressions is true, it will only return false if all of them are false, which is exactly the functionality we are looking for. But we can do even better than this. We don't really need this array as a stored value. We can call some directly as a replacement for map and return it directly. So we can do that now. Give this some and return gonna format that. And there's one minor, minor optimization we can still make. And that is if the query is empty, then we return true. So that is if you're not searching for anything at the time, for example, you can imagine if the search bar is empty, then we're going to return everything anyway. And our filter function, as we look at our Dataflow, filter function won't be removing or hiding any widgets and will be mapping all of them. As we expect. We can also choose to add a lowercase to this. I think that it's a more flexible search if you add these lowercase calls. And we also want to make the query to lowercase, but that depends on your use case. And you could even add this as another parameter. For example, should be case sensitive. And do that here. So if, if it should be case sensitive, it will remove these lowercase convergence. Else you would include them. So we can keep that in our signature. And I am going to say false, we don't want it to be case-sensitive. And now we can add this same type of call to the person list. And just to keep it more legible will just change the name of the variable. And we see already Type Script is complaining. And what did we say? We wanted to perhaps search on firstName, lastName, and eye color. And we see that IntelliSense is already giving us some suggestions for those parameters. And we'll also leave that case insensitive. And since we have this empty query optimization that returns true, we shouldn't see any change in our application. We should still see all of the data listed as this is kind of a pass-through for now. So in this lesson, we created a robust generic search that can search a list of data based on multiple keys. And it maps over each of those keys and will return true if just one of those keys includes the query. And so for now we just have a simple empty query. But in the next lesson we'll start hooking up a interactive UI and we can actually test our search function in real time against both the widgets and the people data. 7. Creating a Search Input for Our Generic Search Function: So in the last lesson, we wrote a fairly advanced generic search function. But so far we're not really using it. We just have a const query, which is an empty string. And that's basically acting as a pass through the filter. And the filter won't do anything. So let's create a React component which actually has a search input and will make the query stateful. So we can actually physically type into a search box and see the widgets and people filtered in real time. So to get started, I'm going to create a new folder called components. And I'm going to create a search input TSX file. And I have a function component boilerplate shortcut here called search input. And basically for the markup, we're going to have a label bootstrap class for a margin top. Since we've been installed. Bootstrap, just say search, try me. That's what the label says. And we need a input for our label, which is the actual search. We're going again use some Bootstrap classes. I'm control and full-width type, placeholder, label. And the onchange event set. We're going to have a set search query function. And all this is going to be, this function here is going to come from our prompts. So we can pass that function down and effectively pass the input search value backup to the parent. So we have to include that in our interface here. What that is is a function which passes a search query, which is a string. And that's void and 3x complaining because I don't have a single node here, nor have I close this one out. Okay? So this looks okay. Let's see if we can use it in our app. We'll put it up here. Search input name was set search query. So now we need a set search query here as well. I mentioned we'll make queries staple. So instead of a single cons two will do the we'll make it stateful. Eu state look. And that will just be a string. And the initial value will be an empty, just as we had above. I have to import that. Awareness is query. Clean this up. And with that, we should be able to use our input. Great, so I just, just looking at three, What else? What can we search for people about Carter? And it's a good one. And just as another quick check we can also, I'm going to activate the case-sensitive functionality that we built. So my search for Carter again, shouldn't work, right? This has to be capitalised. There we go. Even if you see art or there it works. It's actually the sea that takes it away because of the capitalization. Great, so this is working. But there's something I want to illustrate here. That is this onChange event here. Open up the console here in the browser. So every time we tied and even if we've got it very fast typer, we can see that this element buyers a lot. And with such a small and simple UI so far, that's not too much of a problem. But if these lists grow since they're all being kept in the client, we could have some performance issues. And so we're going to improve the onchange event using a custom hook. And so in the next lesson, we will slightly refactor this search input component to use a special use DB ounce function, which will reduce the load that this onChange event causes. 8. Adding a useDebounce React Hook to Reduce Search onChange Event Load: In the last lesson, we created this search input, which has a set search query function as a prop and passes up the changed query into our parent app. And then that query is used in our filter function. But we saw towards the end of the lesson that this function buyers for any change event on the input. And that's a little bit of an overload for our UI. So we're going to use what's known as a DB ounce function to limit the number of calls that are made to set search query in the parent. And so the React way to do that is with a hook. So we'll create that now, creating a new folder called hooks. And this one is going to be called use D balance would be just a plain type script file. And I'll paste that in here. And this was taken from a dev dot TO posts from de Broglie. And the way this works is we can apply it to a part of state in our search input. So we're going to create a stateful query similar to in our app, the initial empty value. Import that. And now what we actually did bounce, I'll call it the D bounced query. We rebalance the actual state variable. And that's in milliseconds. So a quarter of a second should be okay. Now will have to use an effect to actually call this prop. Instead of calling it here, we can use the stateful one. And we'll use that effect. Basically if the query is not empty, we can call the set search query with the d bounced query. Let me add that. And we need to close that. And very important is our dependency array here, which is needed to get this actual rebounds functionality that we want. So we want to include the rebounds query itself and the function that's called. So that dependency array set, like in the last lesson, we can check that our event is firing in a balanced way by adding a little console log. So I'm just going to pop out the query here. We'll still set the query as we need to. But I'm also going to add a console log and firing. And if we start that up, we should see the DB ounce functionality that we want. Okay, so now we typed slowly, should still work. I'll use that Carter example. That's fine. But if we're really rapidly typing, we see that there's a delay to that. I'm firing console on. And we notice there is one small issue and that is when we clear this field or otherwise delete everything, we don't get our full set of results to show again. And that's actually here that I was overly restrictive with this check. Since we are anyway using the DB ounce query as a dependency, this entire US effect is effectively the bounced itself. So we can ignore that and have the app listen even when the D bounds queries empty. So to test that again, again, raising this Carter, we've been clear that we see are full results are back. So in this lesson, we optimize the onchange event by adding a custom use D bounds hook and creating our own internal stateful query within this search input. And it only fires up to the parent when the D bounced query has changed. So in the next lesson, we'll start getting into a generic sorting function for our data. 9. Crafting a Generic Sort Function in TypeScript: In the last lesson, we completed our search input component, which was used to actually change the query, which was used in our generic search function that we wrote. So searches working well in our application and we'll move on to the next functionality in this course, and that is generic sorting. So we saw a little bit of a preview for that, less than three. But there's going to be a special edition to this generic sort, which we'll see shortly. So to get started, we'll start just as we did with the generic search. And that is tacking on yet another array function here, which is sorted. We know that we get an a and b. And we have to write a comparator function, which for us will be generic sort. We'll pass both at a and b. And then again, we have to consider what other values we want to pass, just like we did in our generic search. In this case it's similar. We need to sort on some property in the widgets or the people. And so for now, I'm going to keep this kind of pattern and we'll decide that we will sort based on the title. So obviously, this generic sort doesn't exist yet. So we'll create that right alongside the generic search. We will export it as a function. Again, this is generic. And we'll use our brackets in T. We have a which is type d, b which is type T. And our property which is qi of t. For now this is a simple comparative function. B sub property. This is just like we saw in lesson three. You can save that input that we actually don't need these brackets. It's fine. And next comes the challenge which I alluded to earlier in the course. And the search function is relatively simpler in that were probably only going to search on string-based types within our two types. So for the person that's firstName, lastName Eichler. And for the widgets, that's only title and description. It's okay for us to hard code those properties when we need to call our generic search function. But the challenge with sorting is it's not quite like search where we can build a all or nothing type function where if just one matches, we can display it. A sorting function only makes sense if it operates on a maximum of one property. So we're not going to really get away with hard coding a single property. So in the next lesson, we're actually going to use a new type which can carry around this property that we want to sort with and can keep track of it as the property may change throughout our UI. 10. Creating a Generic Sort React Component: In the last lesson, we created a generic sort function. But we discussed how in this case, as opposed to the search, generic sort really doesn't make sense to have a hard coded category or property to sort on. We can imagine this will probably eventually becomes something like a drop-down where you could select to sort by the title, are sorted by the description or any of these. And so it doesn't make sense to be hard coded like properties to include in the search. So the first thing we wanna do is define this property not as a string, but a stateful value. So we can define that again using the US State hook. And now we have the question of what are typing is going to be. So I'm going to create a new type called i property, which itself will be a generic PIF. And for the widgets, we can keep the title as the initial. The first, let's create this property. And so we can create classes and functions as generics, but we can also make interfaces generic. And so this type will simply be having the property, property where that property has to be a key of the type passed in to ei property. So we'll need to pass that key here. In our case, It's high widget will need to import as well. It's not just a string, but it is property. And this becomes property on property. And actually because of this typing, we won't be able to share the query like we were able to in generic search. So I'll make a second property. I'll actually rename this to widget sort property and set widget soil property. And this one is going to be people are property. And set. People sorted property. And for the people, the person, let's just use the first name as the first, the initial property to sort on. So I'm gonna put that here and we'll copy that over. We never put this onto the array manipulation. So, right. That is, people sort property. So that's looking okay. And these are not used yet. And one hint that we can take is that we need to create a UI element which triggers an event to actually change or set this property. So alongside of our search input, we're also going to create a sorters component. And for disorders, as I mentioned, we can imagine it can look like a drop down. So that's what we're going to start with. Another margin top from Bootstrap. Tries to be a select. It's fine. And selects are filled with options. And options have both the key value and then some sort of label. So again, we're going to use generics to our advantage here. We don't want to go through and make various dropdowns based on widgets or people or any other type in our application. We want the drop-down degenerate itself, so to speak. And we can do that using generics. So I'm going to make this sorter component generic. And then we'll need the prompts to be generic as well. And when the prompts are generic, we can use a reference object of type T, which we can use in our component. But this is how we can generate our options with the keys and values that they need. So what we can do is object keys of our object. We can map. And each one will return an option in for now both the key and the value can be that string key value. And I need to dereference. Object from the prompts format that. And we can also actually put some substance in our label. For example, sort by E. Save that, and let's try and use it in our app. While the search input can work for both, we can put the sorters under each of the titles for each. And for now we'll be using the first widget as our reference object. You can copy that and do the same for people. Fire that up. Great. So we see for the sorters exactly what we expect, all the properties in widgets. And the same for people. First name, last name, eye color, and birthday. So we're over halfway there. We've got our dynamically generated drop-down working based on a generic type. But now we just need to pass up the event when a user clicks on any one of those properties in the dropdown. So I'm going to add to the prompts a set property function. This will be a key of T and it will be avoided. And that actually fires here. Change. You'll then need to de-reference that from the props set property. And the final issue here is that in vanilla JavaScript, the event dot target tau value is simply a string. And we're requiring that this property specifically is a qi of t. So in this very special case, because we know our types explicitly and we've defined them ourselves. This AI person and I widget. We know that it's safe in this case to be able to write this as any. Because we know this value is always going to be a key of the object. Another issue is that we can only get to string keys in this object dot keys. The reason this isn't qi of ti is because in the JavaScript world, the real JavaScript world, objects can have a lot more keys at runtime. Even though in this case, we know for a fact that we've strictly type are types to be these two strip types. So some could argue this as a hack. But in this case because we know the key is explicitly, it's safe for us to use. So saving that, we can go to our app and apply the set property callback. So for the widgets, it's going to be setting the property and nearly the same or the people. But it will be the people served properly. You can even see their type script is so smart that even though we haven't explicitly defined I person here, type scripts actually looking into this object, seeing that this is type T, seeing that this is the generic type t, and that this property is therefore a key of AI person. So actually, it's quite incredible type script can do. Even though we haven't even explicitly called typing in our component. It can do it just from this alone. So I do that. And we should be all set. Let's see if it works. Title looks good. We really can't sort by more than what we have rendered. Otherwise, we can't really tell what's going on. But so far, it looks like it's working. 11. Improving the Application's UI - Bootsrap and react-moment: So in the last lesson, we built a generic React component which could render this drop-down just based on the keys in our widget and people type. But we saw towards the end of the lesson that we can't really visually check if the sorts are working because we haven't really rendered enough yet. So in this lesson, we'll take a step back from generics and just do a little bit of styling for our application so we can see if all these sort functions are working. So to get started, I'm going to create a renderer for our widget. So we're basically going to create two rendering components, one for the widget and one for the people. And they'll basically go here in our mapping function. So we'll be able to move out this markup and put it into a rendering component. So under components, I'm gonna make a new folder called renderers. And for the first one, I'm going to create a widget render. And here we actually don't need a special interface or the props. We can have the prop, the widget itself. And now the two renders that we'll be making don't have to be generic. In this case in our application, they're used only once and they only have a single purpose and that is to be rendering their respective types. So in this case there's no need to use generics. And so for the widget render, I'm gonna get started with some Bootstrap classes, which will make our cards look really nice. And if you remember, we had that special class Boolean, which I said we'd have some fun with. And we'll use that here to add a special class that's basically all the property will do. It's going to have an extra class called special card. And then we'll have the car body. One for the card title will be the title. And let me just let me go ahead and pull all these off. The widget will have more. We're gonna do some card text. The description of the widget. And then card text. Italic, where the rating and the rating is out of ten. Then we'll have a card footer, which will have the ID. So use the pound sim. We'll use the pound symbol for the ID. And we want to add the created an updated date. Now we could, we could just do the raw dates, but those will end up being printed as in the javascript format, which is kind of ugly. So we're actually going to use the React moment package, which comes with a moment React component, where you can do a variety of formatting and neat manipulation on your dates. So I'm going to back out of the running application here. And we're going to install both moment and react moment. So we're going to use the built in moment component. And you can pass the date in this way. And we also want the updated data. That will also be the moment component. They updated. Let's add all these scription rating created, updated and the ID. Now with these dates. And other cool feature of this component is you can simply add the from now prop. And that will add the wording like two weeks ago or four months ago or however long ago the date occurred. So that's really neat and powerful feature in this moment component from React moment format that now everything looks okay. We can go back into our app and we can replace this with a widget render. And we can just spread. This widget is already of Type II widget. And that's the prompts we expect. So we can just spread. The widget directly into that component. And we can start up our app to check it out. Ok, so we've got our data rendering, but we still don't have the Bootstrap styles in yet. We've installed the package, but we need to include it in the application. So we're going to go into the index. This is the entry point of our app. And from the bootstrap docs, they tell you to import from Bootstrap CSS and bootstrap.css. And I also mentioned that we have this fun class which we also haven't created yet. We can do that now. So I'm gonna make a new folder called Styles and a file called styles.CSS. And I'm just going to copy and paste this in. This is just a linear gradient editor. And you'll see in a moment what that's gonna look like. But I'll put this in the course notes. So we can save that file and we have to import that as well in the index. Now if you get this error, this is a node Sass version error. And so the resolution there is to first uninstall node Sass. And we want to install the 4.14.1 version. Excellent. So we see our bootstrap styles are here and are fun. Custom special card with this cool linear gradient is also here. And we see that are react moment component is working. We have a month ago, three months ago. So that's working. We just need some spacing there. So it can move this down. Should do the trick. Perhaps two. Yes. And also in between in between the two. Don't turns out we don't need to singles fine grid, so that's looking good. And now let's do the same for the people type. So we're also going to make a people render. And again, we don't need this interface. We already know exactly what we want. And that is I person. And so we know already just like in the Widget render, i'm gonna go ahead and pull everything right off the prompts. So we've got firstName, lastName, birthday, and eye color are all going to come from the prompts. We're gonna steal the same card markup. And we don't need this special card logic, just use standard bootstrap class card. And we'll do an h3 for the firstName, lastName. And just for fun, we'll add an icon here. I always use this emoji keyboard. I can create a link in the show notes. But that's here. You can search bus. That'll work. Then we're gonna do an unordered list. The first item will be the Eichler and make a bowl. And the second list item will say birthday. And again, we will leverage the moment component past the date right in. And we're not going to use the from now. That doesn't really make sense in this case when we are listening a birthday, but instead we can use the format prop. And I'm going to format it to the long version of the month, then the day. So this would be single digit. There would be no leading 0 if it is single digit. And then the whole year. So format this is looking okay. We'll hop back into our app and do the same as we did for the widgets. Can get rid of this. And we can call or write person render. People render. And again, we can just spread person right into that component. Great, so this is looking good. And we can also add just for fun again, perhaps a little birthday cake here. And we're gonna use some spacing again. And I noticed the spacing is a little off also here in the title. Ship that out. Format this again. And that's looking pretty good. Now that we have this bootstrap markup, we see that the page is pretty long. You've gotta scroll pretty far down to check out both lists. So we're going to do one last little trick. Just the toggle the view between the two. So we're going to make another staple variable. I'm just gonna call it show people. And then we've got the setter. That's going to be just a Boolean. So initially, we won't be showing the people. And we're gonna make a button. It's going to have some text button we can style with the bootstrap styles. And onClick. I'm just gonna make a function that calls the setter set show people. And it's going to set whatever, kill people isn't. So it's going to be just a toggle button. So the button text we can set based on the value of show people. So it showed people is true. Then the button is actually going to say show widgets, since it's going to toggle to that state. And otherwise it's going to say, oh people. And so we actually have to use this variable to actually toggle what we're rendering. So I'm going to wrap the whole widget markup in a fragment here. And then just render that based on the value of this Boolean variable. So up not show people. We're going to show the widgets. And of course the opposite for people. If show people and we show those people cards format that check our work. To currently, that's the default. The widgets are showing. That looks okay, there's no people. And we click show people. It's great. The text changes on the buttons. And the people are now showing. And now the original goal of doing all this UI refactoring and improvements was to see how our sort functions are working so we can check all those now. So we've got these are the title, this is the description, the rating ID. So we can check all of these now. So perhaps description. So there's no description. Abc, that looks fine. Do perhaps rating 0101345, that's working. So this is looking fine. Created four months ago, three months ago, two months ago by rays go together yet these are are working and check out the people. So we already saw first name and last name are working. We can do Eichler. So all the blue eyes and brown, and green and Hazel, it's working. And Birthday also working. So in this lesson, we went through our application and created two new renders for our data to render components. And these are not generic because in our application they have a specific job and they're used in a specific place, so there is no need to use generics. We also created a custom style sheet just with our special card class. And we imported both bootstrap and those custom styles to use in our application. So in the next lesson, we're actually going to take a look again at our sorters and add an ascending and descending functionality. 12. Adding Ascending and Descending Functionality to Our Sorter Component: So in the last lesson, we built our UI and we were able to test all the various disorders that are generated from our generic component. But we also saw that it looks like the default sort is ascending only and there's no option and no signal of a ascending or descending. So in this lesson we're going to build out that functionality. So to get started, we're going to look in our generic sort function. And so the simplest way to add descending functionality to the sort is just a flag. So we'll just do is descending. And that's a Boolean value. And what we can do is instead of going through here and swapping each of the returns, I'm going to wrap this around a function. So just call it resolved. And we're going to return is if it is descending. And we saw that this setup is ascending by default. So if it is descending is true, what we're gonna do is multiply the result by negative one. Otherwise we're going to keep the normal result. That's the ascending result, which seems to be the default of this functionality. It's going to format that. Then of course, as soon as we do that in app, it's going to complain that we didn't pass the is descending flag. So we already see the complication this makes. Just like the property itself. We don't want to hard code this in true or false and lock in the sorted direction for the entire application. So if we look at property here, we see that that's tied to widget. And while the Boolean value itself doesn't have to be tied to any generic. We can probably extend this i property to also carry a Boolean flag. And then we'll be able to set that just as we do the property from the sorters component. So let's extend this i property interface. We'll just do is descending. As a Boolean. It's the default will just set to true. So then in this case, we can also refactor the generic sort signature. Instead of these two together. We can pass the entire thing since we need both anyway. And it already is. The eye property interface will top back in here. And we're gonna combine these. The eye property type. And of course that's generic, but we can pass on our generic. So there's no problem. Now it's gonna complain that these are not set. And so we're gonna just the structure them from the eye property type to rename that perhaps property type format. But so far so good. And now we need to refactor our setting functionality. So let's hop into sorters. Now the set property is going to be not just qi of ti, but the eye property interface. And just to keep with the naming convention that we used in the function itself, I'm going to call this property type. And so the set property has to be extended. We have property. Then we'll need is descending. So to keep using the event target value, we're going to have to extend it beyond just a key name. And so first, I'm going to extend this render function to include a pair of options per key. So we're going to have a descending. So sorted by key, descending and sorted by key. A Sunday, the key will have to be fixed because we don't want repeated keys in our auction listing. In order to create valid HTML, we need to extend the value property because that's what we use in our set property call. So promoted them, we can actually refactor to the same value for each. What I'm going to do is add the the string version of what we'll need for the is descending call. So for the key and the value, we'll do that. Those are true. And then for the ascending version, this will be false. So we see this value is only a string, so we'll have to do a little bit of work on it before calling set property. So I'm going to pull it off. But call a blip on this dash so we'll get the key name itself still. And either true or false. I only wanna do that if values is exactly length two. So, so we know that if this statement is true, the initial value in this value's array will be the key. And the second value will be this, either true or false. But we'll see that Type Script complaints because this is just a string. So in order to convert this to an actual boolean value, we will equate it with the true string. So if this is literally the string true, this will return true. Otherwise, it will be false. And unfortunately, we still need this as any because type script won't recognize that this key is actually a key of T, and we discussed that in the previous lesson. So unfortunately this as any has to remain. And so we can go back to the app. And we don't need the D structuring now because this is the type II property, which is the type that set would sort of property expects. And we can just do that. And we can do the same for the people, save that, and fire it up. And we also need to fix that for the people. Great. So we already see are drop-down is looking okay. And now let's see if it's actually working. So we've got titled descending. That's that default actually that we said looks like it's OK. And then the ascending, which also looks okay. And also do perhaps rating descending. Yep, all tensor up here, 97. So on. Rating a sending is how we saw in the previous lessons. That's also working 56 and so on. Let's check out people. But we already know we should expect it to work because it's running off the same generic function in the same generic drop-down. So we have firstName, yep, all Ss down to a. And first_name ascending is as we saw, a, B and so on grade. So in this lesson, we started off in the generic sort function. Looking at Anne is descending property, which we use to infer the results based on the value of is descending. So if it's true, we would invert these results. If it's false, we will just keep the normal result, which is an ascending ordering. We did this by extending the eye property interface to include the descending property. And we also had to refactor our sorters generic component to include not just stay single option within our select by a pair of options. And we also extended the key and value strings, the key so that it's valid HTML and the value. So we could use it properly in our set property called back up into app. So that's about it for our generic function. And in the next lesson will happen to the third and final generic functionality will be building in this course. And that is a generic filter function. 13. Crafting a Generic Filter Function in TypeScript: In the last lesson, we finished up our generic sort function, adding ascending and descending options. We finally come to the final functionality to build as a generic function in this course. And that is filtering. Filtering in some ways is even more complicated than what we did for sorting. Since filtering itself is a bit weird and not in all cases intuitive. For example, if we look at the widgets and we want to filter by title, it's not initially clear of what exactly that means. Do we assume something like this where there's an empty title should be filtered out? Or do we want to filter out cards or widgets that have completely null or undefined title. You may choose in your own apps to be rather strict on what exact designs decisions to take here. For example, you may want to filter only specific parameters of a type or really not include filtering at all. I think search and sort should get any listing UI pretty high up on the usability scale. In any event, this course is all about the power of generics. So we will be making a super flexible filter functionality. And you can further constrain it or reduce it for your own needs. And as you see fit, the filtering will create in this course will actually eventually end up as a list of check boxes. And you can filter on as many or as few properties as you'd like. So let's hop into the app to get started. So we can start to think about what type of function are generic filter will be. Yep, you guessed it. It's going to be a filter array manipulation. So following this pattern, we can copy this over, but we're not doing a generic search. We're going to be making a generic filter. And we won't need these properties. We will need widget, Of course. But what about the properties that we need? Like I said, we could potentially filter on any or all of the properties within widget. So title, description ID, reading all of these. So for now, I'm going to just make an array of all of the properties. So what do we have? Title, subscription, ID, rating, created, updated, and this special card. And so let's create our generic filter function Now. We'll put that new tools alongside the others. And the others. Create this generic function signature. So we add our object which has type t. And we have these properties. That'll be filter properties. And that's an array. Of p of t. And we know that a filter function has to return a Boolean value. So really, all we need to do is return the true, the or falsy value of the object itself. So what we can do is if we're considering a single property, we would do objects sub property. And if that evaluates to it's true the value, we're going to return true. Otherwise, we'll return false. But of course, we have an array of these properties. And so we'll need to loop at all of them. This is starting to look like our search function where we originally had a map. But we ultimately resulted in using some which returns true if just some of the logic is true for each entity. But actually with the filters I mentioned, we're ultimately going to create a list of check boxes where you can select or deselect as many as you want. So in our case with filtering, if you select multiple filters, we wanna show the matching entities which meet all of those requirements. And so we're going to leverage another array manipulation, and that is the every function. So we can do filter properties. Dot every, and we have just a filter property. And that is going to be this logic here. Type script doesn't complain because filter property is a qi of t. And we're going to return this. So this function will only return true if all of the filter properties we've selected match that property. And so talking a bit more about this Boolean evaluation and true there, falsy. I have a little table here which has all the true the falsy values. So for example, if the object with this filter property is an object itself, this will only evaluate to false. If it's undefined, no, or NaN. If it's a string, the only way it's going to be false is if it's an empty string. If it's a number, it's only going to be false if it's 0. And of course boolean, it's false. It will evaluate to false. Then this value alone isn't necessarily a Boolean value. This could be really any type that we have in our types. So could be a string or a date, or a boolean. It's only that in this boolean context. That is true. The and falsy functionality is activated. So I'll get rid of this comment. And this should be good for now. And we can import this. And I mentioned that as a UI component, these filters will be a list of checkboxes. And in that case, we don't want to actually explicitly filtered by all these properties. But rather this array would be generated based on the checkboxes that the user has selected. So it's not really quite like this hard-coded search function where the searches built-in with these properties or these properties. It's actually more like a stateful variable like in generic sort where we track what property is to be sorted. The only difference in this case is that the filters won't be just a single property, but can be multiple properties. So I'm going to create a stateful variable now so we can track which properties we want to filter out. And I'll call those like the sorting properties, widget filter properties. So we'll be set widget filter properties. And we know that it's an array p of i widget. And actually for an initial value, we'll need an EMT and we'll do the same or the people fill their properties. So I'll copy this functionality here. And just for readability, name this variable Person. So in this lesson, we created our final generic function for this class, and that is the generic filter. In the generic filter function, we pass the generic type t where we reference the object and an array of properties to filter on. And we leverage the built-in every array manipulation function in that we only return true if every filter property that's selected is true. And we discuss what that means in a true the and falsy sense in JavaScript. So in the next lesson, like we did for the generic search and the generic sort, we're going to build a UI component to actually set and manipulate these widget filter properties. 14. Building a Generic React Component for our Generic Filter Function: In the last lesson, we wrote our generic filter function that accepts an instance of the object of type T and a variety of properties to filter on. And it'll return true only if every property past has a JavaScript true the value. And we saw in the App component that we want to track these filter properties, much like we did, the sort properties. So we already start to see that our filter UI component will somehow resemble a little bit the sorters component. We're going to pass in an object of the type that we need. And we'll also have a setting callback, which will actually manipulate the widget filter properties through the stateful setter. So let's get started with our filters component, functional component and filters. So this component will be generic since it'll be used by both the person in widget types. So we can have that everywhere. We said we'll need that object, which will be of type T. And to keep track of what's actually checked in our UI, we're also going to need the filter properties themselves. And that's an array here, T. And let's D structure those right away, since we'll be needing them in the render logic. So I'm gonna just make some nice bootstrap spacing again, padding one on all sides and margin in the y direction of two. And a label like we did for the others. And just say try us too. And this will also have some top margin. And like we did in sorters, we're going to leverage this object dot t's dot map function. So we can copy that. And I mentioned this is ultimately going to look like a series of checkboxes which the user can select or deselect in order to filter. So this will be input type checkbox. The ID is going to be the key itself from our map. The value will also be the key. The onchange function. It's actually going to be the callback which we haven't created yet. So I'm just gonna make it onchange filter. And we'll pass in the key. Let's add that node or properties or props where the component is going to be property, which is a qi of t. And that's a Boyd. Now this is gonna complain. Soon as we included. This will complain like we saw in disorders, that this actual key value isn't truly a qi of ti. But again, we know how we're using it in our app that this is safe to use qi of t. These are flat types and at runtime, we don't expect the keys to change or we know that the keys won't change. So it's safe to use as any in this instance to prevent type script from complaining. And we also need to know if the peg box is actually checked. So here we're going to use the sum array manipulation again. And that is on these, these properties. Basically we, we want to know if the property exists in our list of properties for this key. Close that up and we also add again some, some spacing using Bootstrap utility classes. And I'll also add a label. Again using just the key as the ID. And the label B is true the okay, so this is looking pretty good. Let's hook it up in our app component so we can put it right underneath the disorders. So I'm going to put a break in and we'll have that. And we need to fill our prompts here. So the object. Like in sorters, is just widgets. First index. The properties will be this stateful array. So the widget filter properties and the callback here, onchange filter. So this is going to be a function. We know the property is going to be a key of i widget. And we want to manipulate the widget filter properties based on the property itself. So if the widget filter properties includes property, can do a ternary here. We're going to step B will widget filter properties. As a new array. We always need to create a new state in React. I'm going to spread the existing widget filter properties, but splice out the widget filter properties where the property occurs. So that's the case if the property is already in the filter property. So you can think of this array actually as these are the active list of active filters, since they're exactly what'll be passed into our generic filter function. So if this property is not yet in the Widget filter properties, then we will add it, which is much simpler. We just call the Staples Center. Again with creating a new array. But we're just gonna spread the widget filter properties and also add the property which does not exist in there yet. So that closes up that parameter and that is our filters. So let's fire this up. Great. So we see our filters. There are bunch of checkboxes and let's give it a try air, right? So if I were to check, this is empty description. So in our filter function it'll evaluate as falsy. So bye. So like this, we should see that drop out, right? So that one with the falsy description drops out. We can also check the special cards. We should only see these two. So Title two and z. That looks pretty good. It looks like it's working. So our initial UI component is working, but this is a bit Jeonghye we can't de-select. Or if we do the selected deselects all the others. So let's hop back into the component to fix this issue. And so actually the fix for this Jeonghye UI. With the issue with the de-select here is because I was trying to be too fancy. And that is with this splice call. This splice call is explicitly acting on the state variable, which you never wanna do. So there's actually an easier way anyway. And that is by calling filter, which will return a new copy or a new array which we can use for state. So it's widget filter properties that filter, and we'll just call it Widget filter property. And that is when it does not equal the property. So it'll be this entire array minus whatever property matches our property only in the case when it's already in our array. So I'll format that. And we can check this out now. Refresh the app here. And it looks like it's working. The easiest one here is the is special card. So is true the checked when it's not checked, There's no change to our list. So it looks like it's working. So we can add this component to our people listening as well. So this isn't widgets Now this is people. This will be People filter properties. This will be set people filter properties. Just to rename variable format that no complaints here. Should people. And as I mentioned at the beginning of this lesson, in this case, the filter isn't all that intuitive for people because our data's pretty clean. Everyone has a firstName, Everyone has a last name, everyone has an eye color and everyone has a birthday. So in this case, a filter function doesn't really make sense anyway. And the, the search and orders can be used or make more sense to be used anyway. So in this lesson, we created a generic filter UI component that much like the sort component, used the object keys to generate its content to make this a truly complete solution. In the next lesson, we'll also add a checkbox for each parameter to also allow for falsy. So you can explicitly find objects which the properties are falsy as opposed to those that are truly, we'll look at that in the next lesson. 15. Adding Falsey Functionality to the Generic Filter React Component: So in the last lesson, we created a generic React component which could render these checkboxes based on the properties in our datatypes. And we saw for the case, in people where the data is pretty well structured and there's no missing things that filter for this case maybe isn't very usable. And even in our widgets, only things like special card are really helpful for filtering. But in the very least, we will complete this functionality out with a pair of true the end falsy chat boxes so you could explicitly filter for special card and by the end of this lesson will be able to filter out those special cards. So let's hop into our app to get started. And ultimately what we wanna do is follow the pattern that we set with the sorters. In that we're not just going to pass around properties, but we're going to have an additional property. So in disorders we had this flag is descending. We'll want our own flag is true the selected. So we'll know if we're explicitly filtering for true the more falsy values. So the very first thing I want to do actually is to rename this interface we use for the sorters. I property isn't a very good name and it actually only relates to the sorters. So I'm going to rename that to ice orders. We can save all typed script, automatically updates the names and all those other files. And I'm gonna make the filename match as well. That should be ice order. Save all. And again, I sorter save off. And we're actually going to copy this and make an eye filter in, slightly modify it. So it's going to be I filter still generic. We still pass a property, but along with the property we want is true the selected, and that's a Boolean. And so instead of just a key of II widget, we're gonna have an array of filters of II widget. And then for the person, it will be I person. And so let's hop in our generic filter to handle this update in signature. And this won't be qi of ti anymore. But array of I filter tea. We can import that. And right away we're gonna destructure those properties that we've defined. So we still have the property from the original functionality. But now we have the is true the elected. And if we remember from when we originally wrote this function, writing this statement is implicitly a true the call. So if this is true, the, this will return true. If it's falsy, it won't. But we can refactor the slightly while still relying on JavaScript's true the policy abilities. So this is a Boolean evaluation, but also each side of the ternary can be a Boolean evaluation. So this is our default, is true the selected result. And so I'm going to replace true there. This is our mode of is true the selected. So that's now the operator in our ternary. And we know that this is true the behavior. But if it's not selected, we actually want the opposite behavior. And so if true the selected, we are going to be filtering on those object properties in the sense that a true the value will be put into our filter. But if we've selected the falsy option, we're going to be doing the opposite. So I know it's a bit confusing, but you can throw this into a Chrome terminal and experiment a little bit to see what I mean. But this should give us the functionality that we expect. So I'm gonna save that. And the last thing here is to update our UI, both with the callbacks and typing in filters. So we know now that we're not just setting a qi of ti. But the full property, which is I filter, will import that. And the properties will get is also of the I filter type. And so a lot like we did in the sorters, we're just gonna make a pair of inputs here. One for true, the N14 falsy, just like we did for the descending and ascending. We'll just copy that over. The second one will be ballsy. And now we have to update the signatures here. We can't just pass a key anymore. We also needed pass the d is true the selected. So here we've got the property is true, the selective. We know here, since this is our policy option, this can be hard coded as false. So I'm gonna copy this. And likewise for the true, the option. We can hard code that as true. Since these are always the true the labels. And to make valid HTML, we need to do what we did. For disorders. We don't want repeating IDs. So we can just do something like this. This can be a false, even though we're not using the ID explicitly. We should still make sure we're rendering valid HTML. Now we can hop back to our app and we're going to have to beef up this logic in the unchanged filter callback. So before we had the luxury of using the includes since property with just the string, but now it's the I filter type. So what we'll do instead is see if there's a matching filter. We'll use the filter property. Should be property. So we want this property to equal the property. And also the is true the selected value to match up as well. Then we know we have this specific filter property. And then instead of includes, this becomes greater than 0. So if it's already included, will filter it out. Otherwise we extend the array and this filter will also have to be also adding. This is true the selected. So then we're only filtering out those which are checked, which me exactly both criteria, both the property is true, the selected. So it's almost working, but we also have to improve the function in the filter itself. So we can keep this includes call here anymore either. So instead I'm going to refactor this to a sum call where we'll be able to. Have the property itself and its checked only if the property matches the key. And if the property is true, the selected is true. So we can just leave it there, it's, it will be evaluated as a Boolean. So we can copy this. And the only difference will be that the is true, the selected should be false. And save that. And it looks like our UI is working. And the falsy to check that looks like that's working as well. That chops out those special cards. When is special card falsy? Now there's one last thing. And that's the question. With these pair of checkboxes. Actually, what we should do here is make for each pair of true the falsy in a given key, we can leave them as checkboxes, so they're also d selectable. But we should add some logic to ensure that only a maximum of one is selected at each time. And actually to get that maximum one prepare selected functionality, we can actually go back a bit and reduce the logic in somebody's functions. So the first is, I don't really like this length greater than 0. So I'm going to convert this to a sum. So it's just a Boolean value. Will place that just is match. And so in this case, we don't need to worry about is true the selected. We know that if we found a match here, we want to filter out the match that we found and then just add the new incoming property. Because we know it will be of the opposite is true. The selection pressures at the refactor, this, this has to be an array now. And we have to spread this filter function. We can save that. Refresh the app. Let's try with R is special card still working and then we can go Palsy, which deselects. And we don't see any special cards in here, so those are working there targetable. And selecting others doesn't affect them. So that's great. But there's still one more thing remaining. And that is, if we only have a single, we can't remove the Czech. So we can't completely remove a filter on a given property. So let's fix that as well. So really what it is is an additional case. So this set state we saw toggles properly, but we also need a set state where we remove. The property completely. So first I'm going to rename this is match to property match. And then I'm going to copy this code and add the is true the comparator as well. And I'm going to call this a full match. So while the term area was cool here, we unfortunately have to say goodbye to it. Now we have a logical if, else-if and else case. So the first full tree is full match. And we can actually copy what we originally had. And that is just this pure filter. So there's a full match. That's the un-check event. And we can filter that out. If there is a property match. We can call this logic. And then otherwise we are just appending. We haven't seen the property yet. So we can format that. This should give us the functionality that we need. So again, let's use the special cards since that's the easiest one to visualize. So we have the true these. We have it swapping to falsy and they're not here. And we can also de-select now. So let's check the truth as well. Great. So now everything is working. And now that we have this kind of pair functionality, let's just reformat how they're rendered so we can visualize them better. So I'm going to put a break for each pair and also a break above the label. Just so they're easier to read. Great, so it looks like everything's working. So in this lesson, we added an explicit way to filter out those properties which are falsy. And we made it so you could at most Select or just de-select and not have any filter on that property. And again, this filtering isn't so intuitive. You would probably be filtering on at most something like a category, which would probably be a string value I could imagine for something like an e-commerce shop where you just want to filter by t-shirts or hoodies or hats or things like that. So all in all, this filter function might be a bit of overkill in that you probably wouldn't need to filter. For example, if a title is true there falsy. But this was just another example of the power of generics. And perhaps you can find a use for it somewhere in your applications. So we've successfully created a generic filter, a generic search, and a generic sort. And along with that, we built a search input sorters and filter components which are generic based on their types. The thing to note now is that the App component has kind of become a mess. And there are two issues here. One is that we always have to pass in this object reference to those components which use generics. And another is that we're doing nearly the same thing for both the people and the widgets. We have these three function calls and then a map to our renderer. So in the next two lessons, we're first going to address this issue of passing in the object reference, but then ultimately creating a single component that can orchestrate the types and all this markup for any given type. So we won't have to repeat the markup. And all of these will be refactored into one more complex component. 16. Render Props, or Children as a Function in React: We've come a long way in this course. We've written a generic search, generic sort, n, generic filter functionality. But this left our app component kind of a mess. So in this lesson, we're going to look at how we can remove this object dependency and do a bit of neat react type script refactoring where we can pass children as a function. And those children will be typed according to what our component needs. This lesson, however, is just kind of a look into neat functionality with React. And while we'll use this solution in the final solution, that final solution won't be built until next lesson. So let's get started with refactoring this object parameter. The main problem with this object parameter is the case where widgets is empty. So of course, we've imported them from our mock data. But if you are loading them over an API or from somewhere, this would throw an error if widgets was empty. So it would be best if we didn't pass the entire widgets and handle them within the component itself, then we don't have to depend on passing a single entity of it. We have all of them. And we'll be able to render them from within the component as we'll see shortly. So let's first get rid of this object, prop for the sorters. And I'm going to create a new property called DataSource. And we'll pass in all the widgets here. Well top and disorders to fix that signature. So you don't need object anymore or at least that's what I'm claiming. And instead we're going to have a data source. And this is going to be an array of T. So the first thing we wanna do is fixed. This will make our own object. So we'll do if the datasource dot length greater than 0, we can use the first element. Otherwise, we're just going to pass an empty object. That'll work fine with object dot keys. Because if we call object dot keys on an empty object, we see that it's just an empty array. And so this render function won't be called. That's no problem. And now the next issue is how we're going to actually render these widgets. So the rendering becomes the responsibility of disorders themselves. And we don't do it separately here in this parent app component. So we're going to utilize a quite powerful feature with reactant type script. And that is creating our own type to allow or children as a function. So we know that there is a Built-in prompts with children type, which itself is a generic. We can look at that. We import that. Take a look where p are your own custom props and the children are React Node. So these are the actual children of your component. For example, if I'm an app here, it would be this content here. So if I had a header, I would be able to call in disorders in the render. I would just call children and that H1 tag would be rendered. But we have an array of data here, an array of widgets of i widget. And we don't want to explicitly list in J Sx, something like where we would go through each widget and so on. That just simply isn't feasible. But there is a way to convert this child to a rendering function. And ideally we would want something like this. Where somehow internally we have a call back, which has the II widget type, and we can pass read into our widget renderer. So right now it's already complaining widget has implicitly any type, but reactants and complaining. So we just need to get type script to agree with this type of format and we'll be all set. So I'm actually going to take the prompts with children type. And we're going to create our own here. It will be nearly the same. But instead of children being a static property, we're going to make it a function and it's going to accept a generic. So we'll extend the standard PI or prompts type with the type we want. And I'll also rename. It says prompts with children function. We don't want to override the React type itself. I'm also going to use that here. And then we need to pass that secondary generic type in. And I also need to import React node. And we don't need this anymore. So now we can actually pull children off of our props. And to actually render them. We would first make sure that children is true. The that is. We see that this is an optional property, copying from the original prompts with children in React standard. And so if that isn't set, it'll just be undefined. This'll fail. That's why we check children first. And we also want to make sure our datasource is set, since that's ultimately what we're going to use to render our properties. And we know that data sources and array of t. And so we can just map. In this case, it is a widget. And we can just call the children function, which we know accepts this widget type. So if we go back up top to add type script is so smart that it looks into here, into this type and sees that this function has type t. And so we already know that it's a widget. If we were to change this to people, we would see that Type Script types this as a person. Because this datasource is t, it all flows back into this t. So it's perfect for this use case. So everything is okay there. Now we have to do the same. So our signatures are correct for people. So we're gonna do datasource people. And we're also going to define the render function here. I'm just gonna call it person, so it's easy to read. And since the people render and we can spread the person into that. And so that was an important just from one of the examples. And we should be all right. Exactly. So now we see the disorders or disorder component is here, but it's also rendering these tiles as well. And we know because we see again our original render from the AP. So, so far this is working. But now we have an additional advantage in that because we have access to our children. We can move all the sorting functionality into disorders. And we can call that just before the map. So, so far we've been building our generic component here, but we've been passing the set property event backup to the app, where this state variable is changed. In the widgets are property and people who are property. So we can move all this logic into sorters. And the word widget really can fall out now because this will just be a stored property. Not of any specific type. Poor state. Instead of calling the set property, we don't need it as a prop anymore. The actual stateful property of this component, we can call set soil property. We will need to pass in is an initial property. So that will come from the prompts. Better name actually is initial sort property to be a qi of t. Now we can also move the Generic Sort call before rendering. And again, this isn't the widget stored property, but the sort of property itself need to import that. And we also need to ensure that we pass that initial soil property. This is not a property anymore. We don't need to call that function anymore here in the parent. Just need to pass an initial sort property. And I had title. We need to do the same for people. Get rid of that. Set the initial sort property. We had firstname, I believe an app, of course, yes, these file well, they use elsewhere. I've I've left the original rendering just as a compare, just for now, but we should see that this sore should affect these children Exactly. And so this children as a function technique is very powerful. That is, if you only are doing a single data manipulation, for example, if you're only doing sorters, or you're only doing filtering, or you're only doing search. And the problem is with this type of markup, we're not able to wrap multiple functionality around this datatype. Because as soon as we tried to wrap, for example, if we tried to wrap filters around here, this is also a child. And this is not a function, so we can't repeatedly use this typing. So this typing is very neat and it's really powerful, but it's only going to work for a single array manipulation. So in this lesson, I showed how you can refactor rendering and the logical responsibility into the component itself. And before I push the code for this lesson, I'll do the same for the filters and the search, but just know in the end, you'll have three renderings of three lists. And each list will only be able to be effected by its parent component. That is, you'll have a list for search. And the search will only affect that list. You'll have a list for sorters and assert will only affect that list. And you'll have a list for filters, and we can only filter on that list. So ultimately this is not a final solution. We're getting there, we're getting close. But in the next lesson, we'll start with this refactored code and ultimately create a component which combines all the refactoring into a single powerful component that can orchestrate all the functionality we need. 17. Creating a Single Generic Component to Unite Search, Sort, and Filter: So in the last lesson, we went into search input. And we saw how we could leverage this type, which we've created, mimicking the React standard type of prompts with children. But we changed it to allow for children as a function. And another advantage we saw is that we could move all the state variables and the search logic itself of actually filtering the array into the component itself. And so I went ahead and did that with the sorters and filters, as I mentioned in last lesson. And this is ultimately what we end up with. So we lose almost all the state variables except for this toggle button, which is okay because that belongs to the app itself. But we lose a lot of imports and a lot of messy state. And they've all been encapsulated into their respective components. And so the thing to notice now is that for both widgets and people, they look basically identical. And this is assigned to us that each of these then could be refactored into a component themselves, where we have perhaps a data source to pass a few search settings like the search keys and the initial sort property. But otherwise, we should be able to refactor both of these into a single generic component and will finally arrive at our final solution. So to get started, I'm gonna take all of this markup. It's going to copy that and create a new component. Search, sort and filter ESX. We're gonna combine everything into this component. So I'll paste that in, need the fragment. And so while we showed that this is a neat children has function usability and they can be separated into each. We're actually going to take a step back. And we're actually going to take a step back from a few lessons previous, where we're only rendering once. So in the end, we can start working towards that markup here. We're going to actually have something like this, what we had in each of the separate components. This is going to be moved here in the render below each of the input. Disorders and filters. And then these will become flat components, so there won't be any nesting there. And that's what we're going to work towards in this lesson, is refactoring each of these. So the state and everything is hooked up properly again. So I copied from the filter, but we can also get the, the sorted function. And all the while. I'm going to get rid of the rendering. In each of these children. We won't be doing that anymore. The call that's looking pretty good so far. Then we will use, since we're using this type of children as a function, we will use that type we created. And this component itself of course, will also be generic. So the problems will be generic. And this, and we can look at our markup to figure out what sort of props we want to look at or prompts that we want to consider. So we have a title, datasource, some search keys, and initial sort property, and perhaps a few other. So let's, let's start with title. And we've got our data source. The search keys may actually going to update the name of search keys. That's kind of a poor name. I'm gonna call them search properties. Those can also be a prop, so that's an array of p of t. And initial sort of property. This will eventually be an eyesore order of t import that we should add that this type itself. And we can start de-referencing, restructuring all those props that we need, subtitle, datasource, search properties, initial sort property. They're all from prompts. And we can use them here. We're going to replace widgets with the title. Data source becomes simply a data source. Search properties or the search properties are basically taking out. We're going through all this markup really in just removing any, anything that's could be hard-coded, we're creating a prop. That's all we're doing. Time courses are type. We have children available to us. And we've renamed the search keys are now called search properties. So we will need a search query. Soil property filtered properties. Now, things like the search properties, which are basically static, we only pass them wants, those are fine as prompts. But to properly orchestrate all these moving parts and these filter and sort calls, we're going to also have to add state to this component. So I'm going to create a state interface as well. That's also going to be generic. And we'll have it start with the search query string. The third property, which is a disorder of T, And the filter properties which will be array of I filter type t. And we can also like with the prompts, are gonna D structure those. We're gonna call state and then will use the we use the reactor you state to get the state variable and a setter tuple. And we can type that. The nice thing here is with our props. We can set the initial values. So search, query, I'm just going to leave empty for now. But the sword property can come from the initial sort of property. And we can also do the same for the filter properties. Gonna make initial filter properties. Add that to the props. And array. I filter. This is a comma here. And we'll just destructure all those from the properties. So in order to do that fancy child rendering, we put all the state into our components. So that was just an example to show how you could collect. Everything into the component, but in this case were orchestrating everything and calling the functions here in the parent. So we're actually going to move all of the state back up into here. But since we have our stay object, it's still going to be a little bit cleaner than what we originally had an app here with the multiple use state calls. So it'll be one piece of state. It will be more complex. But in the end we only have our prompts and a single state object to orchestrate the entire searching, sorting and filtering. So we'll get started with the search input and then go on through into disorders and filters and move the state into this parent component. And so we don't need children or the datasource anymore. And this search queries already, we've already handled it up an apparent we don't need that anymore. But we will need to have the callback to set the search query. And that's going to be a string. And avoid function. Just seeing this set search query. We don't need the data source anymore. That should do for now. And get rid of that. And that's okay. Don't need the datasource. And with such search query. And here we have in the callback, the search query. And what we'll do here is call on our set state function. And we're going to spread the original state or the existing state, but modify. What we know is going to be modified from this callback, which is the search query. And that's the shorthand object notation. So this is the same as as this, but since the names are identical, it's, that's fine. It will set the value at that key. Ok, so that's search input. Now in sorters, we still do need that DataSource only because we need to use the object dot keys methodology, getting our keys in, creating the markup. So we still do need the data source for that purpose. But we don't need the children anymore. We can get rid of that. And now we can get rid of this prompts with children function type. We don't need the initial sort property that's handled above. Get rid of that. Right. We'll need the need to define the callback now. And this is also a void function. The structure and the prompts. And this doesn't exist anymore. So that's looking okay. Clean up all these inputs we don't need anymore. And we have to wire up the sensor property. This is gone. And just like with the set search query, it's going to be a very similar function. Got the third property. Basically you gonna copy this. And instead of the search query, it's the sword property. Looks OK. Now looking filters this. We also still have to keep the data source. We can get rid of prompts with children type. We don't need that anymore. We don't need children is following that. We will need to pass the properties themselves, the filter properties as a prop, since they're used here in the logic and also in the checked logic. So I filter t and then that call back, just like all the other components. The set filters property. So filter properties. Spin is this. And again, that's a void. And we had to pull these prompts as well as the set filter properties. So that's looking okay. And we don't need this children rendering anymore. So that's the thing. Okay, we can clean up these imports to wire up local properties. And the set builder properties callback. Copy this. This is insertProperty, but builder properties set bracket. Okay, so let's clean this up. See we have so far looking OK. One thing that sticks out to me is this empty string can also create an initial search query. Perhaps if you're routing and you wanted to route to a page with your search box already full. You could do something like this. After pass that through from the prompts. We'll put that here. Add that to the signature, just a string. And we can add that as well. We should pass that into our search input. It's just a string. Can pull that off the prompts instead of an empty string here, use the stateful one. And to get that actually show up, we need to add the value to the input, this query. So okay, code can clean this up. And we've got a pretty good start on this third Sort and Filter component. So let's try and use it in the app. So I'm gonna leave this here for reference. Let's see what we need here. Going to import this. So it got title, which is going to be widgets. We've got the search properties are going to be these guys. Now we need our data source here and we need the datasource widgets. The initial sort property we have there is title. And I've initial filter properties, which is just an empty array and the initial search query. So I'm also going to leave this the empty shrink for now. It's complaining here. And now we have mass has to be of the sorter type. So we have property and is sending set to true another bracket. And now we have this prompts with children function or calling that children widget. So we need that same type of call in the children markup, something like this, this function markup. And our case here it's a widget. It's a widget render and we spread the widget. So we can clean that up. That's looking pretty good. Basically copy this and just convert it. To how we want to use it for the people. People, people we have first name, last name, eye color, copy those over to our search properties. The initial soil property firstName, looks good, and this is people render, and we can just rename this. And all of this falls away. So we can format that these Dropout and we can piles up. Okay, so the first thing, we've got a maximum update depth exceeded issue. And that is in the search input. So let's take a look at that. And the problem is actually in this dependency. If we go up here and we see what that's called, what we're really doing is updating the state here. And since search query is just a string, it's a primitive. There is no reference to that string. So this components always seen, even if it's just the empty string, this component always sees a new string and that's why it re-renders. So in our case, we can get rid of this. And we know that the callback function itself will never change. So Eastland is complaining that it's a missing dependency. But really we only want to use this effect when the D balanced query changes. So we can hide that complaint with the epslon. Disable. Next line, react hooks, exhaustive depths. So we can save that. Let's go back here, refreshes. Ok, it's looking pretty good. We get our rendering, all our UI components that we built, what see if the functionality works. So I say type, it looks good or see, yep. What else can I search for? Three? That's looking fine. Id, that's looking good. Okay. Those are working fine. Good are our filters. All that's looking fine. And still we retain all the functionality of this. Toggle, the two pair and also the de-select. So everything's looking good there. And now to make this super clean, let's just go through each of these errors and clean them up, and then we'll be done. So the first one is the search input here, and that's that we don't need the generic anymore. We're actually not using any generic types and we don't need this children function. I forgot to take that out. All these t's follower, we don't use them anywhere. Only that type. And say that we don't have any errors from the type-check from type script. But we saw in the browser here we have a few key issues. So it's complaining in the Widget render here, so we need to pass a key to our child render function actually. So the widgets have an ID. And actually what we don't have here for people is an ID, right? We just have, if we look at our mock data, we only have the firstName, lastName, Eichler and birthday. So in an ideal situation, this will be coming from an API and probably from a database. So for now, I am going to add an ID. In this kind of, this will illustrate the power of everything we've written here. So even though I'm going to add this ID here, start at 0 and go up. So even though we have to add this ID here, it's not going to break anything in our app because we've got all this great generic functionality. We can just add that right up, head into app.js X and add that as our key person. And say that this should be person actually refresh this. And we have two left. So there's a key issue in sorters and a key issue in filters. So let's head into those NANDA filters here and that's we look check the render method of disorders wherein filters. So we're gonna look in here and that's here in this map. We've got an array and we have no key in this fragment. And unfortunately with this kind of syntactic sugar way of creating a fragment, we can't pass a key. Like this. It's not valid syntax. But what we can do is use the explicit react dot fragment and that has a key prop pass are key in. And then we also have to add that to the bottom here. And we'll do the same for the sorters. Same thing. Yeah, fragment had the key and close that up. Now if we refresh again, great, we have no console errors. We have no type script errors. And our search sort and filters are working as they did. Just one last thing here I can illustrate how that initial search would work. Just to check that it's, it really is working. If we go up to the app here, we can add, since we're in widget view, I'll add pipe as the initial search query. We go here, refresh. We see that that's being populated properly and it's even firing off the function. And now keep in mind with this orchestration component that combines all of them. We really are filtering, sorting, and searching on these properties. And actually this, this should be cleaned up. We shouldn't have any references to any of these names. They're all generic. So let me just do a double-check here. Shouldn't see any widget and any person or anything like that. Okay? So yes, these are all done in series. And so if we have something like this checked and with Type Script church, there's nothing there. So we have z entitled to. So these are really all working altogether and acting on our list before it's rendered. We can even add here to the people renderer. How did I done the ID here, float left. We can steal that markup after this div. And we don't have the Raider updated, but we have the id which we can now Paul. And I'll just add a little label. Great, so that's working just fine. Just a fun little side. No, I just noticed within the people, if we go to the ID is falsy filter, we actually do get one result and that is this person with an ID of 0. And that's because in a Boolean evaluation in JavaScript, 0 is falsy. So that's just an interesting side effect, but it kind of illustrates why this generic filter isn't exactly that useful for things like numbers or perhaps other things like objects. So in this lesson, we took a look at App and saw that we had a lot of repeated markup that could be even further reduced into a single generic component. And in this generic component, we refactor the search input sorters and filters, and we move the state into a single state object in this parent function here. And we saw it with a bit of refactoring the actual setting of the state is just the spread operator and then manipulating the part of state that the component deals with. We then continue to leverage the prompts with children function, but only using it in a single location here in our composition component. And in this render, recall the generic search, generics or engineering filter before Mapping and rendering out to our render component of choice, which is in the parent. So ultimately we end up with these two nice components which are configured for their respective types. 18. BONUS: Using the Extract TypeScript Keyword to Improve our Generic Sort Function: As a final bonus lesson, let's take a look into our generic sort function. At this moment in time, the sort function is actually a little too flexible. So for example, if one of our types here in AI person or I widget is for example, a function. And we look in generic sort. How can we sort on a function, so to speak? Well, we really can't. So we should extend our qi of t within I sorter here to use only those certain types which we can actually sort. And so far we are only using the greater than or less than comparators. And as far as I know in JavaScript, those only applied to dates, numbers, and strings. So we will define exactly those in our extracted types. And the way to do that in type script is to use the Extract keyword. And so from the qi of t, we want to extract only strings, dates, or numbers. We can save that. And to illustrate that I'm not lying, we will add a additional parameter. Maybe we'll just call it some function. And it's a void. And we'll actually add that to the data as well. And typed scripts already complaining here. Since this is an array of widgets yet we need to add our new property. And we'll just do refresh our app here. And so we will see it here. In the dropdown. We didn't build any sort of type guards in the sorters map, so it will still be rendered here. But the important thing is that our app won't crash. When we try to call that. It's going to enter the generic sort function. And since the type won't match, nothing's going to happen here. And we also noticed that in the filters that this is still here. And this is fine if function itself is actually just an object. And as long as that function is defined in the JavaScript world, that's true. The, so we see that we don't have any where some function is falsy because I've added this function to all of our widgets. So just to quickly recap, we constrained our properties allowed by editing the ice order type in that we extracted only things which used the greater than or less than operator properly. And that is strings, dates, and numbers. 19. Course Review and Final Comments: So in this course we started off by bootstrapping and application with Create React app. And I went through a few initial examples of using generics in type script and how they can help us both with reusability and also how they can protect us from making mistakes. By the end of the lesson, we had created three unique generic functions. One for search, one for sort, and one for filter. We worked through various ways of rendering them. First doing most, all the work in the app. Then we looked at how we could refactor and US children as a function to return the functionality to each of its respective UIs. And then ultimately we ended in our, so to speak, final solution with this search sort and filter component, which ultimately.