Blog Post

Understanding Generics in TypeScript: Part 1

Illustration: Understanding Generics in TypeScript: Part 1

TypeScript is a well-known programming language that adds type safety to JavaScript, and generics are one of the features that make it popular among developers. This blog post is the first in a two-part series, and it’ll discuss generics, how to use them, and how they work in TypeScript.

What Are Generics?

Generics are a way of writing code that can be reused, and they enable us to create functions, classes, and interfaces that can handle any type of data. As a result, the code is more adaptable, easier to change, and easier to maintain.

In TypeScript, generics are denoted by angle brackets <>, and they can be used in three different ways:

  • Generic functions — A function that can accept and return any type of data as an argument.

  • Generic classes — A class that can work with data of any type.

  • Generic interfaces — An interface that can define a contract for any type of data.

Now, let’s take a closer look at each of these.

Generic Functions

A generic function is a function that can work with any data type. The following is an example of a generic function that takes two arguments of the same type and returns their sum:

function add<T>(a: T, b: T): T {
	return a + b;
}

In this example, we use the type parameter T to indicate that the function’s arguments and return type are of the same type. We can use any data type — such as numbers, strings, or arrays — to call the function:

const result1 = add(3, 4); // Returns 7
const result2 = add('john', ' doe'); // Returns "john doe"
const result3 = add([1, 2], [3, 4]); // Returns [1, 2, 3, 4]

Generic Classes

A generic class is a class that can work with any data type. The following is an example of a generic class that stores an array of elements of a specific type:

class List<T> {
	private items: T[] = [];

	add(item: T) {
		this.items.push(item);
	}

	get(index: number): T {
		return this.items[index];
	}
}

In this example, we use the type parameter T to indicate the type of elements that the List class can store. We can create an instance of the List class with any data type, such as numbers, strings, or objects:

const numbers = new List<number>();
numbers.add(1);
numbers.add(2);
console.log(numbers.get(0)); // Returns 1

const strings = new List<string>();
strings.add('john');
strings.add('doe');
console.log(strings.get(0)); // Returns "john"

Generic Interfaces

A generic interface is an interface that can define a contract for any data type. The following is an example of a generic interface that defines a contract for an object with a specific property:

interface Data<T> {
	value: T;
}

In this example, we use the type parameter T to indicate the type of the value property of the Data interface. We can use this interface to define objects with different types of values:

const numberData: Data<number> = { value: 1 };
const stringData: Data<string> = { value: 'hello' };

Conclusion

Generics are an essential feature of TypeScript, and they provide a way to write type-safe and reusable code. In this blog post, we looked at the basic use cases of generics. In part 2, we’ll take a look at advanced use cases of generics. By understanding both the basic and advanced use cases for generics, developers can take full advantage of the power and flexibility that TypeScript provides. Whether you’re building a small application or a large-scale project, generics can help you write more efficient, maintainable, and scalable code.

Author
Ritesh Kumar Web Engineer

Ritesh loves to write code, play keyboard, and paint. He likes working on projects that involve developer tooling, design systems, and music. He wants to make art a part of everyone’s life by using technology.

Explore related topics

Related products
Share post
Free trial Ready to get started?
Free trial