iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

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-

Test yourself

Q1. Format is…
Q2. Best for recall is…
Q3. Each lesson has…

Discussion

Loading…