ShaharAmir
← Back to Blog
TypeScript3 min read

TypeScript Generics for Beginners

Write flexible, type-safe code that works with any type

S
Shahar Amir

TypeScript Generics for Beginners

Generics look scary but they're just placeholders for types. Let's demystify them.

The Problem

You want a function that works with any type:

typescript
123456
// Without generics - loses type info
function first(arr: any[]): any {
return arr[0];
}
const num = first([1, 2, 3]); // type: any 😕

The Solution: Generics

typescript
123456
function first<T>(arr: T[]): T {
return arr[0];
}
const num = first([1, 2, 3]); // type: number ✅
const str = first(["a", "b"]); // type: string ✅

T is a placeholder. TypeScript figures out what it is from usage.

Basic Syntax

typescript
123456789101112131415
// Function
function identity<T>(value: T): T {
return value;
}
// Arrow function
const identity = <T>(value: T): T => value;
// Interface
interface Box<T> {
value: T;
}
// Type alias
type Container<T> = { item: T };

Multiple Type Parameters

typescript
123456
function pair<A, B>(first: A, second: B): [A, B] {
return [first, second];
}
const result = pair("hello", 42);
// type: [string, number]

Constraining Types

Limit what T can be:

typescript
12345678
// T must have a length property
function logLength<T extends { length: number }>(item: T): void {
console.log(item.length);
}
logLength("hello"); // ✅
logLength([1, 2, 3]); // ✅
logLength(123); // ❌ Error: number has no length

Real-World Examples

API Response Wrapper

typescript
12345678
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
type UserResponse = ApiResponse<User>;
type PostsResponse = ApiResponse<Post[]>;

useState-like Hook

typescript
12345678910
function useLocalStorage<T>(key: string, initial: T) {
const [value, setValue] = useState<T>(() => {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initial;
});
return [value, setValue] as const;
}
const [user, setUser] = useLocalStorage<User>("user", defaultUser);

Object Key Access

typescript
1234567
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: "John", age: 30 };
const name = getProperty(user, "name"); // type: string
const age = getProperty(user, "age"); // type: number

Default Types

typescript
123456
interface Container<T = string> {
value: T;
}
const a: Container = { value: "hello" }; // T is string
const b: Container<number> = { value: 42 }; // T is number

Mental Model

Think of generics like function parameters, but for types:

typescript
12345
// Regular function: value parameters
function add(a: number, b: number) { ... }
// Generic function: type parameters
function wrap<T>(value: T) { ... }

When you call the function, you pass values. When you use the generic, you pass types (or let TypeScript infer them).

That's it. Generics = type placeholders. Start simple, and you'll get comfortable fast.

#generics#types#fundamentals

Stay Updated 📬

Get the latest tips and tutorials delivered to your inbox. No spam, unsubscribe anytime.