Skip to content

Advanced Generics in TypeScript

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: "Alice", age: 30, email: "alice@test.com" };
const name = getProperty(user, "name"); // type: string
const age = getProperty(user, "age"); // type: number
type IsString<T> = T extends string ? "yes" : "no";
type A = IsString<string>; // "yes"
type B = IsString<number>; // "no"
type Unpack<T> = T extends Array<infer U> ? U : T;
type StringArr = string[];
type ElementType = Unpack<StringArr>; // string
// Type-safe event emitter
type EventMap = {
userCreated: { id: string; name: string };
userDeleted: { id: string };
error: { message: string; code: number };
};
class TypedEventEmitter<T extends Record<string, unknown>> {
emit<K extends keyof T>(event: K, data: T[K]): void {
console.log(`Event: ${String(event)}`, data);
}
on<K extends keyof T>(event: K, handler: (data: T[K]) => void): void {
// Register handler
}
}
const emitter = new TypedEventEmitter<EventMap>();
emitter.emit("userCreated", { id: "1", name: "Alice" });

Easy: What is keyof used for with generics?

Medium: How does the infer keyword work?

Hard: Design a type-safe event emitter using generics.