TypeScript11 min read19,234 views

TypeScript Generics Explained with Examples

Understand TypeScript generics with practical examples. Learn how to write reusable, type-safe code that works with any data type.

Youssef Boubli

Youssef Boubli

February 28, 2024

Share:
TypeScript Generics Explained with Examples

What are Generics?

Generics allow you to write flexible, reusable code that works with multiple types while maintaining type safety. Think of them as "type variables."

Basic Generic Function

Without generics, you'd need to write separate functions for each type:

typescript

1// Without generics - repetitive
2function identityString(arg: string): string {
3 return arg;
4}
5
6function identityNumber(arg: number): number {
7 return arg;
8}
9
10// With generics - reusable
11function identity<T>(arg: T): T {
12 return arg;
13}
14
15// TypeScript infers the type
16const str = identity("hello"); // type: string
17const num = identity(42); // type: number

Generic Interfaces

Create flexible interfaces that work with any type:

typescript

1interface ApiResponse<T> {
2 data: T;
3 status: number;
4 message: string;
5}
6
7interface User {
8 id: number;
9 name: string;
10 email: string;
11}
12
13// Usage
14const userResponse: ApiResponse<User> = {
15 data: { id: 1, name: "John", email: "john@example.com" },
16 status: 200,
17 message: "Success"
18};

Generic Constraints

Limit what types can be used with extends:

typescript

1interface Lengthwise {
2 length: number;
3}
4
5function logLength<T extends Lengthwise>(arg: T): T {
6 console.log(arg.length);
7 return arg;
8}
9
10logLength("hello"); // ✅ Strings have length
11logLength([1, 2, 3]); // ✅ Arrays have length
12logLength({ length: 5 }); // ✅ Object with length
13logLength(123); // ❌ Error: number has no length

Generic Classes

Create type-safe data structures:

typescript

1class Stack<T> {
2 private items: T[] = [];
3
4 push(item: T): void {
5 this.items.push(item);
6 }
7
8 pop(): T | undefined {
9 return this.items.pop();
10 }
11
12 peek(): T | undefined {
13 return this.items[this.items.length - 1];
14 }
15}
16
17const numberStack = new Stack<number>();
18numberStack.push(1);
19numberStack.push(2);
20console.log(numberStack.pop()); // 2
21
22const stringStack = new Stack<string>();
23stringStack.push("hello");
24stringStack.push("world");

Multiple Type Parameters

Use multiple generics for complex scenarios:

typescript

1function pair<K, V>(key: K, value: V): [K, V] {
2 return [key, value];
3}
4
5const result = pair("name", "John"); // type: [string, string]
6const entry = pair(1, true); // type: [number, boolean]
7
8// Real-world example: Map function
9function mapArray<T, U>(arr: T[], fn: (item: T) => U): U[] {
10 return arr.map(fn);
11}
12
13const numbers = [1, 2, 3];
14const strings = mapArray(numbers, n => n.toString());
15// strings type: string[]

Utility Types with Generics

TypeScript provides powerful built-in generic types:

typescript

1interface User {
2 id: number;
3 name: string;
4 email: string;
5 password: string;
6}
7
8// Partial<T> - All properties optional
9type PartialUser = Partial<User>;
10
11// Pick<T, K> - Select specific properties
12type UserPreview = Pick<User, 'id' | 'name'>;
13
14// Omit<T, K> - Exclude properties
15type SafeUser = Omit<User, 'password'>;
16
17// Record<K, V> - Object with specific key/value types
18type UserMap = Record<string, User>;

Conclusion

Generics are essential for writing professional TypeScript code. They enable you to create flexible, reusable components while maintaining full type safety. Master these patterns and you'll write better TypeScript.

Tags

TypeScriptGenericsJavaScriptProgrammingType Safety
Youssef Boubli

About the Author

Youssef Boubli

Front End Developer & UI/UX Designer from Morocco

View Full Profile →