cefn
cefn

Reputation: 3321

Typing this.$store within a Typescript Vue2 component

Starting from a minimal Vue2+Vuex typescript app created with @vue/cli. I want to ensure references to this.$store.state within a component are of the correct type declared by the Vuex store and its modules.

How can I achieve this? Without intervention, all references to this.$store resolve to Store<any>.

In this commit I changed the default src/store/index.ts created by @vue/cli to introduce a message property in the store...

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

interface RootState {
  message: string;
}

const state: RootState = {
  message: "olleH",
};

export const store = new Vuex.Store({
  state,
  mutations: {},
  actions: {},
  modules: {},
});

In this commit I updated shims-vue.d.ts to read as follows following guidance online to add global typed references to the Vue VM (I suspect the approach only applies to Vue3 though, given the URL of this documentation is next.vue...)...

import type { HelloStore } from "./store";

declare module "*.vue" {
  import Vue from "vue";
  export default Vue;
}

declare module "@vue/runtime-core" {
  interface ComponentCustomProperties {
    $store: HelloStore;
  }
}

Attempting to get autocompletion support within VSCode for this.$store.state still doesn't give me a message property.

I can't find any guidance for how to achieve this for Vue2 anywhere.

What is the pattern I should use so that this.$store gets the proper typing within my Vue2 components using Vuex3. It seems crazy that you can't get properly typed values with the latest stable releases of these tools. What have I missed?

The repro at https://github.com/cefn/vuex-store-typing is my reference case for anyone wanting to experiment.

Upvotes: 2

Views: 2678

Answers (1)

tony19
tony19

Reputation: 138276

The module name you're using in your type augmentation is for Vue 3 only (the code is slightly different in Vue 2), but support for type augmentation of the $store instance property was only added in Vuex 4. It's not possible in Vuex 3.

However, you could actually use the exported store instance (already typed as HelloStore) instead of this.$store, as they're the same instance:

import store from '@/store' // store type is HelloStore

export default {
  mounted() {
    console.log(this.$store === store) // => true
  }
}

Upvotes: 3

Related Questions