Web Development
TypeScript
Subjective
Oct 04, 2025
How do you implement a type-safe event system with payload validation?
Detailed Explanation
Use discriminated unions for event types, mapped types for event-payload relationships, and conditional types for type-safe event handling.
Basic Event System:
type EventMap = {
'user:login': { userId: string; timestamp: Date };
'user:logout': { userId: string };
'post:created': { postId: string; authorId: string; title: string };
'post:deleted': { postId: string };
};
type EventName = keyof EventMap;
type EventPayload = EventMap[T];
class TypeSafeEventEmitter {
private listeners: {
[K in EventName]?: Array<(payload: EventPayload) => void>;
} = {};
on(
event: T,
listener: (payload: EventPayload) => void
): void {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
(this.listeners[event] as any[]).push(listener);
}
emit(event: T, payload: EventPayload): void {
const eventListeners = this.listeners[event];
if (eventListeners) {
eventListeners.forEach(listener => listener(payload));
}
}
}
// Usage
const emitter = new TypeSafeEventEmitter();
emitter.on('user:login', (payload) => {
// payload is typed as { userId: string; timestamp: Date }
console.log('User logged in:', payload.userId);
});
emitter.emit('user:login', {
userId: '123',
timestamp: new Date()
}); // Type-safe
// emitter.emit('user:login', { userId: 123 }); // Error: number not assignable to string
Advanced Event Validation:
type ValidateEventPayload =
T extends EventPayload ? T : never;
function createTypedEvent(
name: E,
payload: ValidateEventPayload, E>
): { name: E; payload: EventPayload } {
return { name, payload };
}
// Usage
const loginEvent = createTypedEvent('user:login', {
userId: '123',
timestamp: new Date()
});
Benefits:
• Compile-time validation of event payloads
• Type-safe event emission and handling
• Prevents invalid event data
• Excellent IDE autocomplete for events.
Discussion (0)
No comments yet. Be the first to share your thoughts!
Share Your Thoughts