DEV Community

Dharan Ganesan
Dharan Ganesan

Posted on

Day 43: Generics

we'll dive into TypeScript generics, exploring what they are, why you should use them, and how to wield their full potential. Let's get started! ๐ŸŠโ€โ™‚๏ธ

What Are TypeScript Generics?

At its core, TypeScript generics provide a way to create reusable, type-safe components. They allow you to write functions, classes, and interfaces without committing to a specific data type. Instead, you can use placeholders (typically represented by T, U, or other descriptive names) that get replaced with actual types when you use the generic component.

function identity<T>(arg: T): T {
    return arg;
}
Enter fullscreen mode Exit fullscreen mode

T is a generic type parameter. When you call identity(42), TypeScript infers that T should be number. When you call identity("Hello"), T becomes string. Neat, right? ๐Ÿ˜Ž

Why Use TypeScript Generics?

  1. Type Safety: Generics ensure that your code is type-safe. They catch type-related errors at compile-time, saving you from runtime headaches.

  2. Reusability: Generics promote code reuse. You can create functions and classes that work with a wide range of types, reducing duplication.

  3. Flexibility: Generics give you the flexibility to work with different data structures without sacrificing type safety. Think arrays, linked lists, trees, or custom data structures.

  4. IDE Support: TypeScript's IDE support is top-notch. With generics, your code editor can provide intelligent suggestions and autocompletions.

How to Use TypeScript Generics

Functions

function reverseArray<T>(arr: T[]): T[] {
    return arr.reverse();
}
Enter fullscreen mode Exit fullscreen mode

You can call this function with any array type.

const numbers = [1, 2, 3];
const reversedNumbers = reverseArray(numbers);

const fruits = ["apple", "banana", "cherry"];
const reversedFruits = reverseArray(fruits);
Enter fullscreen mode Exit fullscreen mode

Classes

Generics are not limited to functions. You can use them with classes too. Imagine creating a Stack class:

class Stack<T> {
    private elements: T[] = [];

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

    pop(): T | undefined {
        return this.elements.pop();
    }
}
Enter fullscreen mode Exit fullscreen mode

This Stack class can work with any data type:

const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
const poppedNumber = numberStack.pop();

const stringStack = new Stack<string>();
stringStack.push("hello");
stringStack.push("world");
const poppedString = stringStack.pop();
Enter fullscreen mode Exit fullscreen mode

Constraints

Sometimes you want to narrow down the types you can use with generics. You can do this using constraints. For example, you might want to create a function that works only with objects that have a length property.

function getLength<T extends { length: number }>(obj: T): number {
    return obj.length;
}
Enter fullscreen mode Exit fullscreen mode

Now, you can't use getLength with just any type; it must have a length property.

const array = [1, 2, 3];
getLength(array); // Works

const str = "Hello";
getLength(str);   // Works

const num = 42;
getLength(num);   // Error: 'length' does not exist on type 'number'
Enter fullscreen mode Exit fullscreen mode

Top comments (0)