DEV Community

Safal Bhandari
Safal Bhandari

Posted on

Understanding Generics in TypeScript

Generics are a language-independent concept (they also exist in C++, Java, and many other programming languages). They allow you to write flexible yet type-safe code that can handle different data types without sacrificing compile-time checks.

Let’s understand them step by step.


1. The Problem

Suppose you need a function that returns the first element of an array. The array can contain either strings or numbers.

A simple solution could be:

function getFirstElement(arr: (string | number)[]) {
    return arr[0];
}

const el = getFirstElement([1, 2, 3]);
Enter fullscreen mode Exit fullscreen mode

This works — but there are problems.


Problem 1: Mixed types allowed

Since we used a union type (string | number)[], users can mix types in the same array without TypeScript raising an error:

const el = getFirstElement([1, 2, "3"]); // No error
Enter fullscreen mode Exit fullscreen mode

This is not ideal if we want type consistency.


Problem 2: Return type inference fails

If we call the function with only strings:

const el = getFirstElement(["harkiratSingh", "ramanSingh"]);
console.log(el.toLowerCase());
Enter fullscreen mode Exit fullscreen mode

We expect el to be a string. However, TypeScript infers the return type as string | number, forcing us to add extra type checks.


2. The Solution – Generics

Generics let us parameterize types, meaning we can write functions, classes, and interfaces that work with any type while maintaining type safety.

A simple example:

function identity<T>(arg: T): T {
    return arg;
}

let output1 = identity<string>("myString"); 
let output2 = identity<number>(100);
Enter fullscreen mode Exit fullscreen mode

Here, T is a type variable that represents the type provided at the time of function call.


3. Fixing the Original Problem with Generics

We can rewrite our function using generics:

function getFirstElement<T>(arr: T[]): T {
    return arr[0];
}
Enter fullscreen mode Exit fullscreen mode

Now:

const el = getFirstElement(["harkiratSingh", "ramanSingh"]);
console.log(el.toLowerCase()); // ✅ Works fine
Enter fullscreen mode Exit fullscreen mode

TypeScript correctly infers that el is a string.


Issue Resolved

  1. Type Safety: If you try to mix different types in the array, TypeScript warns you:
const el = getFirstElement<string>(["harkiratSingh", 2]); 
// ❌ Error: Type 'number' is not assignable to type 'string'
Enter fullscreen mode Exit fullscreen mode
  1. Correct Return Type: TypeScript now knows the exact type of the return value, so we can safely call string methods on it.

4. Key Takeaways

  • Without generics, TypeScript struggles to enforce consistency in scenarios where multiple types are possible.
  • Generics allow you to write reusable, flexible, and type-safe functions.
  • The <T> acts like a placeholder that gets replaced with the actual type during function calls.

In summary: Generics make your code more powerful and safer by combining flexibility with strict type checks. They are a must-know feature when writing scalable TypeScript applications.


Top comments (0)