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:
- Register Actions: Allow components to register specific action handlers.
- Dispatch Actions: Provide a method to trigger a registered action, optionally passing data to it.
- Handle Asynchronous Operations: Action handlers can be asynchronous (e.g., network requests). The dispatcher should manage these gracefully.
- 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
dispatchmethod 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.
registerActionMethod:- Accepts an action name (string) and a handler function.
- The handler function should accept optional
payloaddata and return aPromise(which can resolve with any data or reject with anError).
dispatchMethod:- 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
Promisereturned by the handler. - If the action is not registered, it should reject the returned
Promisewith an appropriate error.
- Accepts an action name (string) and an optional
- 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
ActionDispatcherclass must be implemented in TypeScript. - Action names are case-sensitive strings.
- The
payloadcan be of any type. - Action handlers must return a
Promise. - The
dispatchmethod must always return aPromise. - 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
dispatchmethod 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()andPromise.reject()to simplify returning Promises.