HardPro challengeJavaScriptTypeScript

Strict Type-Safe EventEmitter

TypeScriptTypesEventsPatterns

A plain EventEmitter accepts any string as an event name and any value as the payload — no compile-time safety. TypeScript generics fix that:

type Events = {
  login:  { userId: string };
  logout: void;
  error:  Error;
};

const emitter = new TypedEventEmitter<Events>();
emitter.on('login', ({ userId }) => console.log(userId)); // ✅ payload typed
emitter.emit('typo', {});  // ❌ TypeScript Error: 'typo' not in Events
emitter.emit('login', 42); // ❌ TypeScript Error: payload must be { userId: string }

Your Task

Complete the TypedEventEmitter<TEvents> class:

MethodBehaviour
on(event, listener)Subscribe — returns this for chaining
off(event, listener)Unsubscribe exactly that listener function
emit(event, payload)Call all subscribers for this event with the payload
once(event, listener)Subscribe for a single emission, then auto-remove

Sample tests

Test #1basic on + emit
Input: [[["on","click","h1"],["emit","click",{"x":5}]]]
Output: ["h1:{\"x\":5}"]
Test #2multiple listeners same event
Input: [[["on","msg","h1"],["on","msg","h2"],["emit","msg","hello"]]]
Output: ["h1:\"hello\"","h2:\"hello\""]
Test #3off unsubscribes listener
Input: [[["on","ev","h1"],["off","ev","h1"],["emit","ev",1]]]
Output: []
Test #4once fires only once
Input: [[["once","tick","h1"],["emit","tick",1],["emit","tick",2]]]
Output: ["h1:1"]