TS Exercises
Three short TypeScript drills - a discriminated union, a generic function, and a typed event bus.
Three short challenges
EXAMPLE
// 1. Discriminated union for API responses
type ApiResult<T> =
| { kind: 'success'; data: T }
| { kind: 'error'; message: string }
| { kind: 'loading' };
function render<T>(r: ApiResult<T>): string {
switch (r.kind) {
case 'loading': return 'Loading...';
case 'error': return \`Error: ${r.message}\`;
case 'success': return \`Got ${JSON.stringify(r.data)}\`;
}
}
const userResp: ApiResult<{ id: number; name: string }> = { kind: 'success', data: { id: 1, name: 'Ada' } };
console.log(render(userResp));
// 2. Generic 'pick' helper
function pick<T extends object, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
const out = {} as Pick<T, K>;
for (const k of keys) out[k] = obj[k];
return out;
}
const user = { id: 1, name: 'Ada', email: 'ada@example.com', secret: 'shh' };
const safe = pick(user, ['id', 'name', 'email']);
// ^ inferred as { id: number; name: string; email: string }
// 3. Typed event bus
class EventBus<Map extends Record<string, unknown>> {
private listeners = new Map<keyof Map, Array<(p: any) => void>>();
on<K extends keyof Map>(name: K, cb: (p: Map[K]) => void): () => void {
const arr = this.listeners.get(name) || [];
arr.push(cb as any);
this.listeners.set(name, arr);
return () => {
const a = this.listeners.get(name) || [];
this.listeners.set(name, a.filter((f) => f !== cb));
};
}
emit<K extends keyof Map>(name: K, payload: Map[K]): void {
(this.listeners.get(name) || []).forEach((f) => f(payload));
}
}
type AppEvents = {
order: { id: string; total: number };
user_login: { userId: string };
};
const bus = new EventBus<AppEvents>();
bus.on('order', (o) => console.log('new order', o.id, o.total));
bus.on('user_login', (e) => console.log('user logged in', e.userId));
bus.emit('order', { id: 'ord_1', total: 4990 });
// bus.emit('order', { total: 4990 }); // type error - missing id
// Stretch
// - Add 'once' to the EventBus (auto-unsubscribe after first emit)
// - Use template literal types to derive a list of subscribe shortcuts
Why it matters
Discriminated unions + generics + keyof are the workhorses of TypeScript. These three drills exercise the muscle of designing types that catch real bugs and make APIs self-documenting.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// Fill-in-the-blank: // const greeting: ____ = 'hi'; const greeting: string = 'hi'; console.log(greeting);Try it Yourself »
Exercise
Exercise format.
fill-in-the-
Five letters.
Discussion
Loading…