Day 43: Generics
Tags: javascript, typescript, 100daysofcode, day43
Published: 2023-09-07 13:30:00

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.


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

 `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


```typescript
function reverseArray<T>(arr: T[]): T[] {
    return arr.reverse();
}
```

You can call this function with any array type.

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

const fruits = ["apple", "banana", "cherry"];
const reversedFruits = reverseArray(fruits);
```

### Classes

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

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

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

    pop(): T | undefined {
        return this.elements.pop();
    }
}
```

This `Stack` class can work with any data type:

```typescript
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();
```

### 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.

```typescript
function getLength<T extends { length: number }>(obj: T): number {
    return obj.length;
}
```

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

```typescript
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'
```