Generic classes in TypeScript are useful when you want to deal with multiple data types. A generic class can be defined by having angle brackets containing a generic type parameter list after the class name.

Let’s first look at how we define a regular class in TypeScript.

class List {
  elements: string[] = [];

  addToList(value: string) {
    this.elements.push(value);
  }
}

let list = new List();

We have a class List with field elements and a method addToList() which simply pushes values passed to it. In this example, we can only have an array of strings stored in the elements.

let list = new List();

list.addToList("Hi");
list.addToList("How");
list.addToList("How");
list.addToList("you?");

console.log(list);

If we try to add a number, TypeScript will throw an error.

let list2 = new List();

list.addToList(1); // ❌ Argument of type 'number' is not assignable to parameter of type 'string'.

We can write a generic class if we want to have more control over this class.

class List<T> {
  elements: T[] = [];

  addToList(value: T) {
    this.elements.push(value);
  }
}

let list = new List<string>();

list.addToList("Hi");

The class List is now a generic class that allows us to specify the type of data while creating an instance of a class.

let list = new List<string>();
list.addToList("Hi");

If we want to have an instance of a class that stores only numbers, we can create an instance of a List class as follows:

let list = new List<number>();

list.addToList(1);
list.addToList(2);
list.addToList(3);
list.addToList(4);

Let’s look at another example, with a constructor method.

class Student<T, U> {
  id: T;
  name: U;

  constructor(id: T, name: U) {
    this.id = id;
    this.name = name;
  }
}

let student = new Student<number, string>(1, "Bob");

console.log(student); // Student {id: 1, name: 'Bob'}

Here, we have a class Student that takes two data types T and U. While creating an instance of class Student we can specify both the types that generic types T and U should hold. In this case, we have specified T to hold number and U to hold string as the data types.