0
0
Typescriptprogramming~20 mins

Type-safe event emitter pattern in Typescript - Practice Problems & Coding Challenges

Choose your learning style9 modes available
Challenge - 5 Problems
🎖️
Type-safe Event Emitter Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
Predict Output
intermediate
2:00remaining
What is the output of this type-safe event emitter example?

Consider this TypeScript code using a type-safe event emitter pattern. What will be printed when the code runs?

Typescript
type Events = {
  login: (user: string) => void;
  logout: () => void;
};

class EventEmitter<E> {
  private listeners: { [K in keyof E]?: E[K][] } = {};

  on<K extends keyof E>(eventName: K, listener: E[K]) {
    if (!this.listeners[eventName]) {
      this.listeners[eventName] = [];
    }
    this.listeners[eventName]!.push(listener);
  }

  emit<K extends keyof E>(eventName: K, ...args: Parameters<E[K]>) {
    this.listeners[eventName]?.forEach(listener => {
      (listener as (...args: any[]) => void)(...args);
    });
  }
}

const emitter = new EventEmitter<Events>();
emitter.on('login', user => console.log(`User logged in: ${user}`));
emitter.on('logout', () => console.log('User logged out'));

emitter.emit('login', 'Alice');
emitter.emit('logout');
AUser logged in: Alice
B
User logged in: Alice
User logged out
CUser logged out
DNo output
Attempts:
2 left
💡 Hint

Check how many listeners are registered and what events are emitted.

🧠 Conceptual
intermediate
1:30remaining
Which TypeScript feature ensures type safety in this event emitter?

In a type-safe event emitter pattern, which TypeScript feature is primarily responsible for ensuring that event names and their listener argument types match correctly?

AGenerics with mapped types
BType assertions
CType aliases without generics
DUnion types
Attempts:
2 left
💡 Hint

Think about how the event names and listener types are linked in the class definition.

🔧 Debug
advanced
2:00remaining
What error does this broken type-safe event emitter code produce?

Identify the error produced by this TypeScript code snippet:

type Events = {
  data: (value: number) => void;
};

class EventEmitter {
  private listeners: { [K in keyof E]?: E[K][] } = {};

  on(eventName: K, listener: E[K]) {
    this.listeners[eventName].push(listener);
  }

  emit(eventName: K, ...args: Parameters) {
    this.listeners[eventName]?.forEach(listener => listener(...args));
  }
}
ATypeError: listener is not a function
BSyntaxError: Unexpected token '.'
CTypeError: Cannot read property 'push' of undefined
DNo error
Attempts:
2 left
💡 Hint

Check what happens if no listeners are registered yet.

📝 Syntax
advanced
1:30remaining
Which option correctly types the emit method in a type-safe event emitter?

Choose the correct TypeScript signature for the emit method to ensure type safety for event arguments.

Aemit<K extends keyof E>(eventName: K, ...args: Parameters<E[K]>): void
Bemit(eventName: keyof E, args: any[]): void
Cemit(eventName: string, ...args: unknown[]): void
Demit<K>(eventName: K, ...args: any[]): void
Attempts:
2 left
💡 Hint

Look for the option that uses generics and extracts parameter types from the listener function.

🚀 Application
expert
2:30remaining
How many listeners are registered after this code runs?

Given this code snippet, how many listeners are registered for the 'update' event after execution?

type Events = {
  update: (data: string) => void;
};

class EventEmitter {
  private listeners: { [K in keyof E]?: E[K][] } = {};

  on(eventName: K, listener: E[K]) {
    if (!this.listeners[eventName]) {
      this.listeners[eventName] = [];
    }
    this.listeners[eventName]!.push(listener);
  }

  off(eventName: K, listener: E[K]) {
    this.listeners[eventName] = this.listeners[eventName]?.filter(l => l !== listener);
  }
}

const emitter = new EventEmitter();

function listener1(data: string) { console.log('Listener 1:', data); }
function listener2(data: string) { console.log('Listener 2:', data); }

emitter.on('update', listener1);
emitter.on('update', listener2);
emitter.off('update', listener1);
emitter.on('update', listener1);
A0
B1
C3
D2
Attempts:
2 left
💡 Hint

Count how many times listeners are added and removed.