Beginner's Guide to TypeScript Generics: Writing Flexible and Reusable Code

Learn how to use TypeScript generics to create flexible, reusable code that works with any data type. This beginner-friendly guide explains generics in simple terms with practical examples.

TypeScript is a powerful language that adds static types to JavaScript. One of its most useful features is generics, which allow you to write functions and classes that work with multiple types instead of one. This helps you create flexible and reusable code with better type safety.

In this guide, we'll explain what generics are, why you need them, and how to use them in simple examples.

### What are Generics?

Generics let you define a placeholder type parameter in your functions or classes. This type parameter can be replaced by any actual type when the function or class is used. Think of it like a recipe that can use any ingredient you choose.

### Example Without Generics

Imagine a function that takes an array and returns the first element:

typescript
function firstElement(arr: any[]): any {
  return arr[0];
}

const str = firstElement(["apple", "banana", "cherry"]); // "apple"
const num = firstElement([1, 2, 3]); // 1

The problem with this code is that it uses `any`, so TypeScript cannot check if the returned value matches the input type. This could cause bugs.

### Example With Generics

We can fix this by using a generic type `T` to represent the array element type:

typescript
function firstElement<T>(arr: T[]): T {
  return arr[0];
}

const str = firstElement(["apple", "banana", "cherry"]); // inferred as string
const num = firstElement([1, 2, 3]); // inferred as number

Here, `` declares a generic type parameter. When you call `firstElement`, TypeScript automatically figures out what `T` should be based on the array you pass in. The return type is `T`, so TypeScript knows exactly what type to expect.

### Generic Functions with Multiple Type Parameters

Generics can have multiple type parameters. For example, here’s a function that creates a pair (tuple) from two values of any types:

typescript
function makePair<T, U>(first: T, second: U): [T, U] {
  return [first, second];
}

const pair = makePair("hello", 42); // inferred as [string, number]

### Generic Interfaces and Classes

You can also use generics with interfaces and classes to create reusable data structures.

typescript
interface Box<T> {
  value: T;
}

const stringBox: Box<string> = { value: "hello" };
const numberBox: Box<number> = { value: 123 };

class Container<T> {
  private content: T;
  constructor(value: T) {
    this.content = value;
  }
  getContent(): T {
    return this.content;
  }
}

const container = new Container<boolean>(true);
console.log(container.getContent()); // true

### Benefits of Using Generics

1. **Type Safety:** Generics keep type information, enabling better error checking. 2. **Reusable Code:** Write functions/classes once that work with any type. 3. **Maintainability:** Makes your code easier to understand and maintain. 4. **Avoid `any`:** Helps avoid the problems associated with the `any` type.

### Summary

Generics in TypeScript are a powerful way to write flexible and reusable code while keeping type safety. Start by defining generic type parameters with ``, and TypeScript will help infer the specific types during function or class usage. As you become comfortable, you can explore more advanced generic features like constraints and default types.

Happy coding with TypeScript generics!