Generic classes

We can make a whole class generic. Let's dive into an example of a generic class that stores data in a list:

  1. Let's define our class first without any content:
class List<T> {

}

We mark the class as generic by putting <T> after the class name.

  1. Inside the class, let's create a private property for the data in the list:
private data: T[] = [];

We refer to the generic type using T.  In our example, our data property is an array of whatever type the class has been declared with.

  1. Let's now add a public method to get all the data in the list:
public getList(): T[] {
return this.data;
}

We reference the generic array as the return type with T[].

  1. Let's implement a method for adding an item to the list:
public add(item: T) {
this.data.push(item);
}

We reference the data item being passed in with the generic type T. The implementation simply uses the arrays push method to add the item to our private array.

  1. Let's also implement a method for removing an item from the list:
public remove(item: T) {
this.data = this.data.filter((dataItem: T) => {
return !this.equals(item, dataItem);
});
}
private equals(obj1: T, obj2: T) {
return Object.keys(obj1).every(key => {
return obj1[key] === obj2[key];
});
}

We again reference the data item being passed in with the generic type T. The implementation uses the arrays filter method to filter the item out of our private array. The filter predicate uses a private method that checks whether two objects are equal.

  1. So, now that we've implemented our generic list class, let's create a type and some data in preparation for consuming it:
interface IPerson {
id: number;
name: string;
}
const billy: IPerson = { id: 1, name: "Billy" };
  1. Let's now create an instance of our generic class:
const people = new List<IPerson>();

We put the type we want to use with the class after the class name in angled brackets.

  1. We can now interact with the class by adding and removing billy:
people.add(billy);
people.remove(billy);
  1. Let's try to use a different type with our list instance:
people.add({name: "Sally"});

We get a compilation error, as we would expect:

  1. Let's save all the items in our list instance to a variable:
const items = people.getList();

If we hover over the items variable, we see that the type has been correctly inferred to IPerson[]:

So, a generic class allows us to use the class with different types but still maintain strong typing.

We actually used generic classes earlier in the book where we implemented React class components with props and state:

interface IProps { ... }
interface IState { ... }
class App extends React.Component<IProps, IState> {
...
}

Here, the React.Component class has two generic parameters for the props and state.

So, generics are a really important concept that we'll use heavily in this book to create strongly typed React components.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.14.85.76