Utilize mapGetter and mapMutations in Vuex with TypeScript without the need for class-style components syntax

After completing a project in Vue, I found myself getting a bit confused without static types. To address this, I decided to incorporate TypeScript into my project while still maintaining the traditional way of writing code, without classes and decorators.

Although I have successfully ported my store to TypeScript while sticking to the conventional approach, I am now faced with a new challenge. I would like to utilize mapGetters, mapMutations, and mapActions in my components using TypeScript, but without resorting to class-style components.

import Vue from 'vue';
import { mapGetters, mapActions } from 'vuex';

export default Vue.extend({
  methods: {
    ...mapActions('pictures', ['toggleFavorite']),
    anotherMethodExample: (pictureId: number): void {
      this.toggleFavorite(pictureId); // Unfortunately, an error occurs at this line.
    },
  },
});

The error message reads as follows:

Property 'toggleFavorite' does not exist on type 'CombinedVueInstance<Vue, unknown, unknown, { index: unknown; isSelected: unknown; getToggleFavorite: any; /* other methods */; }, Readonly<{ picture: any; }>>'.

I am struggling to find a solution on how to use mapGetters and mapActions without utilizing the @Component syntax. Personally, I prefer to stick to the "normal" coding style for better readability and ease of reference to official Vue documentation.

If anyone has advice or suggestions on how to overcome this hurdle, I would greatly appreciate it!

Thank you in advance! o/

Answer №1

After encountering a similar issue, I stumbled upon this query. After conducting some tests, I believe I have found a potential solution.

It appears that the root cause, as evident from the discussions, lies in the need to annotate the computed properties. However, there remains an absence of type safety when injecting the mapped methods from the store module.

The workaround involves wrapping the methods mapGetters and mapActions to allow Typescript to infer the types accurately. This approach will flag compile-time errors if incorrect keys are provided to the mapper, ensuring correct return types without resorting to any.

// defining a type that excludes the first context argument
type OmitActionContext<F> = F extends (
  context: ActionContext<any, any>,
  ...args: infer P
) => infer R
  ? (...args: P) => R
  : never;

// signature of action methods
type ActionMethod = (
  context: ActionContext<any, any>,
  ...args: any[]
) => Promise<any>;

// must include extra parentheses for key inference accuracy
// e.g., mapActionsNamespaced<TYPE>()(namespace, map)
function mapActionsNamespaced<
  S extends Record<keyof S & string, ActionMethod>
>(): <Map extends (keyof S & string)[]>(
  namespace: string,
  map: Map
) => {
  [K in Map[number]]: OmitActionContext<S[K]>;
} {
  return <Map extends (keyof S & string)[]>(namespace: string, map: Map) =>
    mapActions(namespace, map) as any;
}

By utilizing the above wrapper, accurate inference of payload and Promise return types is achieved.

Furthermore, an added benefit is the ability to catch typing errors at compile time should you mistakenly append an 's' to toggleFavorite, triggering an intellisense error on compilation.

...mapActionsNamespaced<PictureModuleActions>()('pictures', ['toggleFavorites'])

For a comprehensive solution, refer to the gist linked here

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What function is missing from the equation?

I am encountering an issue with an object of type "user" that is supposed to have a function called "getPermission()". While running my Angular 7 application, I am getting the error message "TypeError: this.user.getPermission is not a function". Here is w ...

Tips for updating parameters that are defined in a controller within a promise

Currently, I am developing a single page application using Angular and TypeScript. I am facing an issue with updating the parameter value (_isShowFirst) of the controller inside a promise function. It seems like nothing is recognized within the promise blo ...

Typescript Error:TS2345: The argument '{ theme: string; jsonFile: string; output: string; }; }' is not compatible with the parameter type 'Options'

Encountering an error mentioned in the title while using the code snippet below: import * as fs from 'fs' import { mkdirp } from 'mkdirp' import * as report from 'cucumber-html-reporter' const Cucumber = require('cucumber ...

The Firebase Authentication JS library does not properly fill the `providerData` array

Within my VueJS / QuasarJS application, I am utilizing firebase-js-sdk [1] in conjunction with firebaseui-web [2] to manage authentication processes. After a successful authentication using any of the configured providers (such as password, google, apple, ...

Conflicting events arising between the onMouseUp and onClick functions

I have a scrollbar on my page that I want to scroll by 40px when a button is clicked. Additionally, I want the scrolling to be continuous while holding down the same button. To achieve this functionality, I implemented an onClick event for a single 40px s ...

Intellisense in VS Code is failing to work properly in a TypeScript project built with Next.js and using Jest and Cypress. However, despite this issue,

I'm in the process of setting up a brand new repository to kick off a fresh project using Next.js with TypeScript. I've integrated Jest and Cypress successfully, as all my tests are passing without any issues. However, my VSCode is still flagging ...

Detecting server errors in Nuxt.js to prevent page rendering crashes: A Vue guide

Unique Context This inquiry pertains to a previous question of mine, which can be found at this link: How to handle apollo client errors crashing page render in Nuxt?. However, I'm isolating the focus of this question solely on Nuxt (excluding apollo ...

Angular Routing can be a powerful tool for managing multiple article posts in an efficient and organized way

I am in the process of building a website with Angular that features numerous articles. Whenever a user clicks on an article, I want it to navigate to a new URL using routing. To achieve this, I have created a new Article component and here is how my app- ...

Is there a way to implement pagination for data in Laravel and Vue.js?

Currently, I am in the process of creating a website using Laravel and Vue.js. My approach involves using a complex Eloquent query to retrieve data from the database, shown below: $query->with([ 'deviceAssignment.deviceSetting.sim', ...

Learn the process of adding files and information to FormData using vue.js

I'm having trouble adding an uploaded file and a data value to FormData in my Vue.js application. Currently, only the files request is being accessed in my controller. data() { return ( file: '', categ: '' } } Here is ...

Vue component not reflecting updated value from axios response

I am struggling to update the temp object after making an axios call. Any assistance would be greatly appreciated. This is the entire code snippet. I have implemented this component in a Vue application. Vue and components are new to me, so any guidance ...

Is there a way to modify the style when a different rarity is selected in Next.JS?

Is there a way to change the style depending on the rarity selected? I am currently developing a game that assigns a random rarity upon website loading, and I am looking to customize the color of each rarity. Here is how it appears at the moment: https:/ ...

Switch up your vuecomponents with Vue.js toggling!

I am currently working on a simple Vue application and I am still getting the hang of Vue.js. In my project, I have two Vue components that I want to toggle between upon clicking a button. My question is whether it is possible to achieve this by using sc ...

Propagating numerical values through iterative iterations

I am currently facing an issue with passing values as props to a component using the forEach method in JavaScript. In addition to passing the existing values from an array, I also want to send another value that needs to be incremented by 1 for each iterat ...

Is it feasible to select which modules to be loaded into the application?

Looking for a solution to my problem outlined in the title. For example, I am tasked with creating two separate versions of an app - one for France and one for the UK. In some areas, they require completely different implementations. Is it feasible to sw ...

Is it possible to adjust the color of the iOS status bar using NativeScript, Angular 2, and TypeScript?

I recently came across this npm package called NativeScript Status Bar, available at the following link: https://www.npmjs.com/package/nativescript-statusbar However, I'm facing an issue because I cannot use a Page element as I am working with Angul ...

Why won't the button's color change when I try clicking on it?

I am currently learning vue and facing some challenges. The code I have is supposed to change the button color when clicked, but it's not working as expected. Any advice on how to fix this issue would be greatly appreciated. Thank you! let app = ...

Is it possible to incorporate @ngrx into a Vue project?

Looking for a state management solution to connect our desktop Angular app and mobile Vue app, both sharing APIs and functionalities. As a newcomer to RxJS and state management tools like Ngrx, I'm curious if there are any hindrances in directing Vue ...

Angular's queryParams do not appear to properly connect with the query parameters

My code seems to have a mistake somewhere, but I can't figure it out. In my [queryParams] = "{allowEdit: server.id == 3 ? 1 : 0}", the params object is empty when I subscribe to it in the edit-server component. Why is it empty and how do I a ...

What is the best way to reset the state in vuex store?

My vuex store contains a lot of data. Is there an efficient way to clear all the state data at once, rather than having to manually set each item to null? ...