Skip to main content
Go back

TypeScript #8: Generics (The Basics)

#typescript #generics #basics

TS most powerful tool. Learn to write reusable and flexible code with <T>.

Until now, our types were fixed. string is always string. But, what if we want to create a function or component that works with any type, but without losing safety?

Here enter Generics. They are like “parameters” but for Types.

The Problem: Duplication or any

Imagine a function that returns what you pass to it (classic identity function).

typescript
// Option 1: Duplicate code for each type
function returnString(val: string): string { return val; }
function returnNumber(val: number): number { return val; }

// Option 2: Use 'any' (We lose the type)
function returnAny(val: any): any { return val; }

const result = returnAny("Hello"); 
// TS doesn't know 'result' is string, thinks it's 'any'.
// result.toUpperCase(); // ❌ No autocomplete

The Solution: Generics <T>

We can tell the function: “Hey, we are going to pass a type to you that we will call T. Use it to type the argument and the return”.

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

// Explicit usage (we pass the type)
const num = identity<number>(123); // num is number

// Inference (TS is smart and guesses it)
const str = identity("Hello"); // str is "Hello" (literal) or string

The T is a convention (comes from Type), but we can call it whatever we want: <Data>, <Response>, <Props>.

Generic Interfaces

This is super common in React or API responses.

typescript
// A box that can contain anything
interface Box<T> {
  content: T;
  label: string;
}

const shoeBox: Box<string> = {
  content: "Nike Air",
  label: "Sports"
};

const giftBox: Box<number> = {
  content: 1000,
  label: "Money"
};

Real Example: useState

If we have used React, we have already used Generics without knowing it.

tsx
// useState is a Generic function: function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>]

// Inference:
const [name, setName] = useState("Alice"); // TS infers that T is string

// Explicit (useful when initial value is null):
const [user, setUser] = useState<User | null>(null);

Let’s try it!

Create a function envolver (wrap) that whatever you put in, returns it inside an array. If you put 10, [10] comes out. If you put "hello", ["hello"] comes out.