Vuex-module-decorators actions are async

June 11th 2021 Vuex

The vuex-module-decorators package makes it easy to create a strongly typed Vuex store for use with TypeScript. However, there are some pitfalls in handling errors in actions.

First, the rawError parameter in the @Action decorator must be set so that the errors thrown are not wrapped, making it impossible to inspect and properly handle them in the calling code:

@Action({ rawError: true })
async throwsAsync(): Promise<void> {
  throw new Error('From async action.')
}

The calling code can now handle the errors in the usual way, using a try-catch block:

try {
  await getSampleModule(this.$store).throwsAsync();
} catch (err) {
  // inspect and handle error
}

However, this does not work with a synchronous action like the following:

@Action({ rawError: true })
throwsSync(): void {
  throw new Error('From sync action.')
}

The calling code can still use a try-catch block:

try {
  getSampleModule(this.$store).throwsSync();
} catch (err) {
  // inspect and handle error
}

But it would not catch the error as seen in the browser console:

Uncaught (in promise) Error: From sync action.

Although the action is synchronous, there still appears to be a promise involved. This can be explained by the following quote from the documentation:

If you are doing a long running task inside your action, it is recommended to define it as an async function. But even if you do not, this library will wrap your function into a Promise and await it.

This is why the code that calls the method synchronously does not catch the error. The method does not throw an error. Instead, it returns a rejected promise. To catch the error, you should treat the method as asynchronous:

try {
  await getSampleModule(this.$store).throwsSync();
} catch (err) {
  // inspect and handle error
}

This works, but it is error-prone because the method's signature is misleading. It does not indicate that it should be called asynchronously due to the transformation by the vuex-module-decorators package.

To avoid this situation, it is best to make all actions in the store asynchronous, even if you do not call any asynchronous or long-running methods in it.

A sample project demonstrating this behavior can be found in my GitHub repository.

The vuex-module-decorators package wraps synchronous actions in a promise. This means that their signature is not correct. To avoid this problem, it's best to make all your actions asynchronous, even if you don't need to.

If you're looking for online one-on-one mentorship on a related topic, you can find me on Codementor.
If you need a team of experienced software engineers to help you with a project, contact us at Razum.
Copyright
Creative Commons License