Using Typescript to define Vuex store types

Attempting to create a TypeScript-friendly Vuex store has been quite the challenge. Following instructions outlined here, I've encountered an issue where accessing this.$store from a component results in a type of Store<any>.

I'm struggling to find a way to make it default to Store<MyState> without needing to cast it every single time.

Answer №1

Regrettably, it is not feasible to replace the existing Store<any> type defined by VueX with a more specific type. One workaround is to introduce a secondary field that provides a properly typed $store, eliminating the need for constant casts or declarations in all components:

import { Store } from "vuex";

// Define $tstore with proper typing equivalent to $store.
// It's impossible to directly override the Store<any> type.
declare module "vue/types/vue" {
  interface Vue {
    $tstore: Store<State>;
  }
}

// Assign $tstore as a getter that returns $store.
Object.defineProperty(Vue.prototype, "$tstore", {
  get: function() {
    return this.$store as Store<State>;
  },
  enumerable: true,
});

Answer №2

If you happen to stumble upon this - we managed to resolve the issue by defining a new type for the constructor's return value -

import Vue, { VueConstructor } from 'vue'
import { Store } from 'vuex'
import { RootState } from '@/store/types'

abstract class CustomVueClass extends Vue {
    public $store!: Store<RootState>
}
const CustomVue = Vue as VueConstructor<CustomVueClass>;

export default CustomVue;

and then simply

export default CustomVue.extend({
    name: 'name',

    components: {
        componentA,
        componentB,
},

this enables us to correctly implement typing:

methods: {
sessionStarted(): Boolean | undefined {
    return this.$store.state.sessionState?.session.started;
},

Answer №3

If you want to ensure typing in your Vue component, one handy way is to declare a property and use the ! operator to let TypeScript know that Vue will handle setting the variable for you. This technique works well with both $refs and $store.

$store!: Store<StoreStateType>;

Another approach is to utilize the MapState or MapGetters component helpers provided by Vuex. These helpers automatically create properties that you can directly use in your template. Here's an example:

@Component({
  computed: mapState({
    userFullName: (state: any) => state.user.fullName,
    userEmail: (state: any) => state.user.email
  })
})

Remember to import necessary dependencies like Store, your Vuex state class, and any helper functions using

import { Store, mapState } from "vuex";
.

Answer №4

I was unable to find a satisfactory answer, so I took matters into my own hands and stumbled upon a fantastic solution. Inside my store.ts file, I simply inserted the following:

declare module "@vue/runtime-core" {
  interface ComponentCustomProperties {
    $store: Store<State>;
  }
}

This snippet transforms the code in this manner:

//store.ts
import { createStore, Store } from "vuex";
import { CustomTool, CustomListType } from "custom";

export type State = {
  tool: CustomTool
  list: CustomListType | null
};

export default createStore({
  state: {
    tool: CustomTool.Empty
    list: null,
  } as State,
  mutations: {},
  actions: {},
  modules: {}
};

declare module "@vue/runtime-core" {
  interface ComponentCustomProperties {
    $store: Store<State>;
  }
}

This solution works perfectly with vue3 and typescript 4.4.

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

Basic cordova application that transfers data from one page to another using typescript

Currently, I am developing an Apache Cordova application using TypeScript. However, I am facing a challenge in passing information from one HTML page to another using TypeScript. I would appreciate it if someone could guide me on the steps needed for nav ...

Error: The data received from the Axios GET request cannot be assigned to the parameter type of SetState

Currently I am in the process of building my initial TypeScript application after transitioning from a JavaScript background. While I am still adjusting to the concept of declaring types, there is a specific issue I am encountering at the moment. The sni ...

Leverage the power of JavaScript functions within the app.component.ts file of

I have a JavaScript file named action.js and I am trying to incorporate it into an Angular project. After doing some research, I found out that the js file should be placed in the assets folder and the path must be referenced in the scripts array within an ...

I am interested in incorporating `connect-history-api-fallback` into my project in Vue.js, but I am unsure about the implementation

After refreshing the page in Vue.js, I encounter an Nginx error. I am currently using 'connect-history-api-fallback', but I'm uncertain about how to implement it in Vue.js. I noticed its usage in app.js with middleware server; how can we use ...

Using TypeScript with Vue allows you to customize the default export of Vue

Currently experimenting with Vue and TypeScript, attempting to compile to AMD in my tsconfig file. The type definition in vue/types/index.d.ts for Vue.js includes: export default Vue; However, this results in TypeScript compiling it like this: import V ...

Showing the selected item and navigating to the items before and after in an array using Vue

I have a pair of elements arranged in two rows side by side: https://i.stack.imgur.com/ymhv3.jpg Both elements have been added to an array of objects and passed through props to be displayed on the left side. My goal now is to set it up so that when a c ...

Searching for multiple filtered items in Vue.js

When working with Vue js, searching through a list is straightforward. However, when dealing with a large dataset of 1000 records and needing to apply specific filters for user searches, I find myself at a loss. Is there a plugin or method that can help me ...

The Vue 3 Composition API - The property retrieved by setup() "is accessed during rendering but is not defined in the instance."

I've been experimenting with Vue 3's Composition API by creating a small in-app message console, but I'm having trouble pinpointing the error in my code. When rendering this component, the state is being accessed during render (in the loop), ...

What is the best way to address a NULL value within a VueJS filter?

This piece of code demonstrates a working filter filteredItems() { return this.items.filter(item => item.name.toLowerCase().indexOf(this.search.toLowerCase()) > -1) } However, my attempt to filter on a second column ...

How to retrieve the path, route, or namespace of the current or parent component/view in a Vue.js application

I have been working on enhancing a sub-menu system for vue.js that dynamically populates based on the children routes of the current route. I recently asked a question about this and received a helpful answer. Currently, I am trying to further improve the ...

Effects of incorporating unnecessary packages on Vue.js performance

In my Vue.js component, I have imported the module useI18n from "vue-i18n" but have not utilized it anywhere within the component. Concerned about how this could affect performance, particularly in terms of bundle size and load times. Will importing a mod ...

Ways to access information and functions from another component

Creating a timer dashboard where alarms can change the background color of the timer. Looking to display the timer on a different page with the set background color from the dashboard, but struggling to pass data between components successfully. http ...

Create and save data to a local file using Angular service

I am facing an issue with my Angular service: import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { person } from '../interfaces/iperson ...

Guide on navigating to a different page using a function with router link in Angular using TypeScript

Trying my hand at Angualar and Typescript for the first time. I am working on creating a login page where users can move to another page if their credentials are correct. To achieve this, I want to use a function that is triggered by clicking a button. How ...

Accessing enum values in a view with Typescript and AngularJS version 1.5

Recently started working with Angular 1.5 and Typescript I have a service that returns data in an array format called devices.headerEntries: [{name:id,value:45} ,{name:Mode,value:1},{name:State,value:2},{name:serialnum,value:123434} I created a componen ...

Mistakenly importing the incorrect version of Angular

While working on my Angular 1 app in typescript, I faced an issue when importing angular using the following syntax: import * as angular from 'angular'; Instead of importing angular from angular, it was being imported from angular-mocks. Thi ...

Securing a single component within a named view router in Vue.js

Within my routes configuration, I have a named view route set up: let routes = [ { name: "home", path: '/', components: { default: Home, project: ProjectIndex } } ] The goal is to ...

Error: Unhandled promise rejection - The function get is not part of this.categoryMap

I am facing an issue with calling functions of the Map (get, set, keys, etc) within my function. The map I am working with is returned from a firebase query. Here's a snippet of my code: categoryMap = new Map<Number, String>(); //called onInit ...

Error during Next.js build: Incompatible types - cannot assign type to 'never'

Encountering an error in the console while attempting to build my project: .next/types/app/facebook/page.ts:8:13 Type error: Type 'OmitWithTag<typeof import("D:/projects/abkh24/client/app/facebook/page"), "metadata" | "defa ...

Customize Vue.js: Disable Attribute Quote Removal for Individual Pages

We have a requirement to turn off the minify.removeAttributeQuotes property for certain pages. This is the content of my vue.config.js: const packageJson = require('./package.json') module.exports = { assetsDir: packageJson.name + &apos ...