mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
62 words
1 minute
A Practical Guide to TypeScript Generics

Why Generics?#

Without generics, you’re stuck choosing between type safety and flexibility. Generics give you both.

// Without generics — loses type information
function first(arr: any[]): any {
return arr[0];
}
// With generics — type-safe and flexible
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
const num = first([1, 2, 3]); // type: number
const str = first(['a', 'b', 'c']); // type: string

Generic Constraints#

Use extends to restrict what types are accepted:

interface HasLength {
length: number;
}
function logLength<T extends HasLength>(item: T): T {
console.log(item.length);
return item;
}
logLength("hello"); // ✅ string has .length
logLength([1, 2, 3]); // ✅ array has .length
logLength(42); // ❌ number has no .length

Generic Interfaces#

interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
interface User {
id: number;
name: string;
email: string;
}
// The response is strongly typed
const response: ApiResponse<User> = {
data: { id: 1, name: 'LeviFREE', email: 'levi@example.com' },
status: 200,
message: 'OK',
};

Generic Utility Types#

TypeScript ships with powerful built-in generics:

interface User {
id: number;
name: string;
email: string;
password: string;
}
type PublicUser = Omit<User, 'password'>;
type UserUpdate = Partial<User>;
type ReadonlyUser = Readonly<User>;
type UserKeys = keyof User; // "id" | "name" | "email" | "password"

Real-World Example: A Type-Safe Event Emitter#

type EventMap = {
login: { userId: string; timestamp: Date };
logout: { userId: string };
error: { code: number; message: string };
};
class TypedEmitter<T extends Record<string, any>> {
private listeners = new Map<keyof T, Set<Function>>();
on<K extends keyof T>(event: K, handler: (payload: T[K]) => void) {
if (!this.listeners.has(event)) {
this.listeners.set(event, new Set());
}
this.listeners.get(event)!.add(handler);
}
emit<K extends keyof T>(event: K, payload: T[K]) {
this.listeners.get(event)?.forEach(fn => fn(payload));
}
}
const emitter = new TypedEmitter<EventMap>();
emitter.on('login', ({ userId, timestamp }) => {
// userId and timestamp are fully typed
});
emitter.emit('error', { code: 404, message: 'Not found' }); // ✅
emitter.emit('error', { wrong: true }); // ❌ Type error

Generics are one of TypeScript’s most powerful features. Once they click, you’ll wonder how you ever wrote code without them.

Share

If this article helped you, please share it with others!

A Practical Guide to TypeScript Generics
https://blog.levifree.com/posts/typescript-generics-guide/
Author
LeviFREE
Published at
2026-07-01
License
CC BY-NC-SA 4.0

Some information may be outdated

Table of Contents