Now that VUE3 is coming to an end, everything has been improved and support for TS is stronger. Vuex4’s support for TS has not changed at all. The useStore type is still any, and the official solution is provided here.

InjectionKey Injection type

  1. Define the type InjectionKey.
  2. InjectionKey provides the type when the store is installed into the Vue application.
  3. Pass the type InjectionKey to the useStore method.
// store.ts
import { InjectionKey } from 'vue'
import { createStore, Store } from 'vuex'

// Manually declare the state type
export interface State {
  count: number
}

// Define the injection type
export const key: InjectionKey<Store<State>> = Symbol(a)export const store = createStore<State>({
  state: {
    count: 0}})Copy the code

Next, pass the defined injection type when installing into the Vue application:

// main.ts
import { createApp } from 'vue'
import { store, key } from './store'

const app = createApp({ ... })

// pass the injection key
app.use(store, key)

app.mount('#app')
Copy the code

Finally, you can pass the key to the useStore method to retrieve typed storage.

// in a vue component
import { useStore } from 'vuex'
import { key } from './store'

export default {
  setup () {
    const store = useStore(key)

    store.state.count // typed as number}}Copy the code

Use the DECLARE Module to override the useStore type

As you can see, by defining a special key, useStore can look up the stored type based on that key and return the correct type. However, there is a bit of trouble here. You have to manually define the type of State, which means that when writing State, you have to write another State interface. And the official instance ignores the type of state in Modules. Here’s a better way to solve both problems

  1. Modify the useStore type based on the current store
  2. Modify the types of modules files with the supplied type data
  3. Use declare Module “”vuex/types” to override incoming generics
// store.ts
import { createStore } from 'vuex'
const store = createStore({
  state: {
    count: 1
  },
  mutations: {},
  getters: {},
  actions: {},});// We can get the type of the current store.state
type StoreStateType = typeof store.state
Copy the code
// modules/common.ts
// Modify a generic function that is only used to keep the type correct in the current storage
import { StoreOptions, Store } from "vuex";
const createModule = <S>(store: StoreOptions<S>) = > store as Store<S>;
// Define a module
export default createModule({
  state: {
    commonCount: 12}});Copy the code

Back in Store. ts, override useStore types with the Declare Module

// store.ts
import { createStore } from "vuex";
import common from "./modules/common";

const store = createStore({
  state: {
    count: 1
  },
  mutations: {},
  getters: {},
  actions: {},
  modules: {
    common
  }
});
// Override the generic default value type in the original useStore function
declare module "vuex" {
  type StoreStateType = typeof store.state;
  type ModulesType = {
    common: typeof common.state;
  }
  export function useStore<S = StoreStateType & ModulesType> () :Store<S>;
}

export default store;

Copy the code

At this stage, I have already guessed the state type of the current state and module. As for magic strings in dispatch, commit and any getters, I have not found an effective solution. The official type is fixed. It is difficult to expose the actions | getters | mutations in key value types, it is difficult to consider the type of, and to dispatch, the commit is not arbitrary string, I ask you a good solution?