DEV Community

Cover image for The ABCs of TypeScript Generics
Manpreet Singh
Manpreet Singh

Posted on

The ABCs of TypeScript Generics

Table of Contents

1. Introduction
2. What are TypeScript Generics?
3. Why Use Generics in TypeScript?
4. How do TypeScript Generics Work?
5. How do TypeScript Generics Work?
6. Conclusion


Introduction

Generics in TypeScript provide a way to make the code more flexible and reusable by allowing the same code to work with different data types. The concept of generics is not unique to TypeScript and can be found in other programming languages as well. In this blog, we will explore what TypeScript Generics are, how they work, and their applications.

What are TypeScript Generics?

TypeScript Generics allow us to write functions, classes, and interfaces that can work with any data type, making the code more reusable. When using generics, we can define a type placeholder, which is a parameter that is used to specify the data type of the elements being processed by the code. This placeholder can then be used throughout the code and is replaced with the actual data type when the code is compiled.

Why Use Generics in TypeScript?

Generics are useful in TypeScript because they allow us to write code that can handle different data types in a flexible and reusable manner. By using generics, we can create functions, classes, and interfaces that can be used with any data type, making the code more versatile and easier to maintain. The use of generics also ensures that the code is type-safe, reducing the risk of runtime errors caused by type mismatches.

How do TypeScript Generics Work?

Generics in TypeScript work by using type parameters. Type parameters are placeholders for the data type of the elements being processed by the code. When the code is compiled, these type parameters are replaced with the actual data type specified when the code is used.

To use generics in TypeScript, we need to define a type parameter when declaring the function, class, or interface. This type parameter is then used throughout the code to specify the data type of the elements being processed.

Let's take a look at an example to see how generics work in TypeScript.

Example 1: Writing a Function with Generics

Consider the following code, which defines a function to find the minimum value in an array of numbers.

function findMin(numbers: number[]) {
    let min = numbers[0];
    for (let i = 1; i < numbers.length; i++) {
        if (numbers[i] < min) {
            min = numbers[i];
        }
    }
    return min;
}
Enter fullscreen mode Exit fullscreen mode

In this code, the function findMin is defined to work only with arrays of numbers. But what if we want to use the same function to find the minimum value in an array of strings or an array of any other data type?

To make the function more flexible and reusable, we can use generics. Here's how the code would look using generics.

function findMin<T>(values: T[]) {
    let min = values[0];
    for (let i = 1; i < values.length; i++) {
        if (values[i] < min) {
            min = values[i];
        }
    }
    return min;
}
Enter fullscreen mode Exit fullscreen mode

In this code, the type parameter T is defined in the function declaration, and the parameter values is of type T[]. The type parameter T is used throughout the code to specify the data type of the elements in the array.

Now, we can use the function findMin with arrays of any data type, including numbers, strings, or any other data type. Here's how we would use the function with an array of numbers:

let numbers = [1, 2, 3, 4, 5];
let minValue = findMin(numbers);
console.log(minValue); // Output: 1

Enter fullscreen mode Exit fullscreen mode

And here's how we would use the function with an array of strings:

let names = ['John', 'Jane', 'Jim', 'Joan'];
let minName = findMin(names);
console.log(minName); // Output: 'Jane'
Enter fullscreen mode Exit fullscreen mode

As we can see, the function findMin can be used with arrays of different data types, making it more flexible and reusable.

Example 2: Writing a Class with Generics

Let's consider another example, where we want to create a generic stack class that can be used with any data type. A stack is a data structure that allows us to add and remove elements in a Last-In-First-Out (LIFO) order.

Here's how the stack class would look without using generics:

class Stack {
    private items: number[];

    constructor() {
        this.items = [];
    }

    push(item: number) {
        this.items.push(item);
    }

    pop() {
        return this.items.pop();
    }
}
Enter fullscreen mode Exit fullscreen mode

In this code, the stack class is defined to work only with numbers. But what if we want to use the same class to create stacks of strings or any other data type?

To make the class more flexible and reusable, we can use generics. Here's how the code would look using generics:

class Stack<T> {
    private items: T[];

    constructor() {
        this.items = [];
    }

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

    pop() {
        return this.items.pop();
    }
}
Enter fullscreen mode Exit fullscreen mode

In this code, the type parameter T is defined in the class declaration, and the type of the private property items is T[]. The type parameter T is used throughout the code to specify the data type of the elements in the stack.

Now, we can use the stack class with any data type, including numbers, strings, or any other data type. Here's how we would use the class with numbers:

let numbersStack = new Stack<number>();
numbersStack.push(1);
numbersStack.push(2);
numbersStack.push(3);
console.log(numbersStack.pop()); // Output: 3
console.log(numbersStack.pop()); // Output: 2
console.log(numbersStack.pop()); // Output: 1
Enter fullscreen mode Exit fullscreen mode

And here's how we would use the class with strings:

let namesStack = new Stack<string>();
namesStack.push('John');
namesStack.push('Jane');
namesStack.push('Jim');
console.log(namesStack.pop()); // Output: 'Jim'
console.log(namesStack.pop()); // Output: 'Jane'
console.log(namesStack.pop()); // Output: 'John'
Enter fullscreen mode Exit fullscreen mode

As we can see, the stack class can be used with different data types, making it more flexible and reusable.

Conclusion

Generics in TypeScript provide a way to write code that can work with multiple data types, making the code more flexible and reusable. By using type parameters and generic types, we can write functions and classes that can work with any data type. This allows us to write code that is not specific to a particular data type, and can be reused for multiple data types, reducing code duplication and improving the overall quality of our code. In this blog, we have seen how to use TypeScript Generics and their applications through two examples, including a generic function to find the minimum value in an array, and a generic class to implement a stack data structure. Understanding and using Generics in TypeScript is an important aspect of writing robust and efficient code, and is a skill that every TypeScript developer should have in their toolkit.

In conclusion, TypeScript Generics provide a way to create generic components and functions that can be used with different data types. They can be used to create flexible and reusable code, making it easier to maintain and extend. TypeScript Generics are particularly useful when working with arrays, classes, and functions, where the same code can be used with different data types. They allow us to write code that can work with any data type, making it easier to write, test, and maintain, while reducing code duplication and improving the overall quality of our code. If you are a TypeScript developer, taking the time to understand and use TypeScript Generics can greatly improve the quality and efficiency of your code.


Hope this is helpful ✨ Do Like ❤️ & Save 🔖

For more Tips 💡 + Guides 📜 + Resources ⚡️ related to Programming, Machine Learning/AI 🤖 , Data Science & Web Development 👨‍💻

Do Follow me on

LinkedIn - - Github - - Twitter - - Polywork - - Instagram - - Medium


Top comments (0)