Hone logo
Hone
Problems

Vue Action Dispatcher

This challenge focuses on implementing a robust action dispatcher mechanism within a Vue.js application using TypeScript. You will create a system that allows components to trigger asynchronous operations or state modifications in a centralized and predictable manner, promoting better state management and separation of concerns.

Problem Description

Your task is to build a basic "Action Dispatcher" for a Vue.js application. This dispatcher will serve as a central hub for handling various "actions." Actions represent specific events or operations that a component might want to perform, such as fetching data, updating user profiles, or submitting forms.

The Action Dispatcher should:

  1. Register Actions: Allow components to register specific action handlers.
  2. Dispatch Actions: Provide a method to trigger a registered action, optionally passing data to it.
  3. Handle Asynchronous Operations: Action handlers can be asynchronous (e.g., network requests). The dispatcher should manage these gracefully.
  4. Provide Feedback (Optional but Recommended): The dispatcher could potentially emit events or return promises to indicate the success or failure of an action. For this challenge, we'll focus on returning a Promise from the dispatch method that resolves with the action's result or rejects on error.

Key Requirements:

  • TypeScript: All implementation must be in TypeScript.
  • Class-based Dispatcher: Create a TypeScript class for the Action Dispatcher.
  • registerAction Method:
    • Accepts an action name (string) and a handler function.
    • The handler function should accept optional payload data and return a Promise (which can resolve with any data or reject with an Error).
  • dispatch Method:
    • Accepts an action name (string) and an optional payload (any).
    • If the action is registered, it should call the corresponding handler with the payload and return the Promise returned by the handler.
    • If the action is not registered, it should reject the returned Promise with an appropriate error.
  • Vue Integration (Conceptual): While you won't build a full Vue app, imagine this dispatcher being accessible within Vue components.

Expected Behavior:

When dispatch is called with a registered action name and payload, the corresponding handler should execute with that payload. The dispatch method should return a Promise that mirrors the outcome of the handler.

Edge Cases to Consider:

  • Dispatching an unregistered action.
  • Handlers that throw synchronous errors.
  • Handlers that return Promises that reject.

Examples

Example 1: Registering and Dispatching a Simple Synchronous Action

// Assume ActionDispatcher is instantiated as 'dispatcher'

// Register a synchronous action
dispatcher.registerAction('greet', (payload: { name: string }) => {
  return Promise.resolve(`Hello, ${payload.name}!`);
});

// Dispatch the action
dispatcher.dispatch('greet', { name: 'Alice' })
  .then(result => {
    console.log(result); // Expected output: "Hello, Alice!"
  })
  .catch(error => {
    console.error(error);
  });

Example 2: Dispatching an Asynchronous Action (Simulated Fetch)

// Assume ActionDispatcher is instantiated as 'dispatcher'

// Register an asynchronous action
dispatcher.registerAction('fetchUserData', (userId: number): Promise<{ id: number, name: string }> => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (userId === 1) {
        resolve({ id: 1, name: 'Bob' });
      } else {
        reject(new Error('User not found'));
      }
    }, 500); // Simulate network delay
  });
});

// Dispatch the action
dispatcher.dispatch('fetchUserData', 1)
  .then(userData => {
    console.log('User data:', userData); // Expected output: "User data: { id: 1, name: 'Bob' }"
  })
  .catch(error => {
    console.error(error);
  });

Example 3: Dispatching an Unregistered Action

// Assume ActionDispatcher is instantiated as 'dispatcher'

// Dispatch an action that hasn't been registered
dispatcher.dispatch('nonExistentAction', 'some data')
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error(error.message); // Expected output: "Action 'nonExistentAction' not found."
  });

Constraints

  • The ActionDispatcher class must be implemented in TypeScript.
  • Action names are case-sensitive strings.
  • The payload can be of any type.
  • Action handlers must return a Promise.
  • The dispatch method must always return a Promise.
  • Performance is not a primary concern for this challenge, but the implementation should be reasonably efficient.

Notes

  • Consider how you will store the registered actions. A Map or an object would be suitable.
  • Think about how to handle errors thrown synchronously within an action handler versus Promises that reject. The dispatch method should consistently return a Promise that reflects the outcome.
  • While this challenge focuses on the dispatcher logic, in a real Vue app, you might inject this dispatcher or make it globally available through a Vue plugin.
  • You can use Promise.resolve() and Promise.reject() to simplify returning Promises.
Loading editor...
typescript