'Vuex modules with typescript

EDIT:
Since vue conference Toronto (late 2021), Vue has officially switched over to Pinia for typescript support, instead of Vuex. They also acknowledge that Vuex was notoriously difficult to work with, while trying to use TypeScript and splitting a store into multiple modules, while retaining most benifits of TypeScript. Therefore this question is no longer relevant.


Original post:
I'm trying to create a staticly typed vuex store with multiple modules. I've read several articles, but must admit that I'm stuck, which is why I'm hoping someone here could help me out. I have currently have 2 modules; documentation and workAgreement, with strongly typed commits and dispatch methods in ..store/modules/{module}/types.ts.

export type AugmentedWorkAgreementContext = {
    commit: WorkAgreementStore["commit"],
    dispatch: WorkAgreementStore["dispatch"]
  } & Omit < ActionContext < IWorkAgreementState, RootState > , 'commit' | "dispatch" >


  export type WorkAgreementStore < S = IWorkAgreementState > = Omit < Store < S > , "commit" | "getters" | "dispatch" >
  &
  {
    commit < K extends keyof IWorkAgreementMutations,
    P extends Parameters < IWorkAgreementMutations[K] > [1] > (
      key: K,
      payload: P,
      options ? : CommitOptions
    ): ReturnType < IWorkAgreementMutations[K] > ;
  } & {
    dispatch < K extends keyof IWorkAgreementActions,
    P extends Parameters < IWorkAgreementActions[K] > [1] > (
      key: K,
      payload: P,
      options ? : DispatchOptions
    ): ReturnType < IWorkAgreementActions[K] > ;
  } & {
    getters: {
      [K in keyof IWorkAgreementGetters]: ReturnType < IWorkAgreementGetters[K] >
    }
  }

This is then made into a type in ..store/index.ts with the following code.

export type RootState = {
  workAgreement: IWorkAgreementState
  documentation: IDocumentationState
}

export const store = createStore({
  modules: {
    documentationStore,
    workAgreementStore,
  }
})

type Store = DocumentationStore < Pick < RootState, 'documentation' >> & WorkAgreementStore < Pick < RootState, 'workAgreement' >>

  export function useStore(): Store {
    return store as Store
  }

From here I'm trying to use it in a component, and it workes to some extend, my problem is that it dosen't help me with the intellisense on one of the modules, specifically whichever one is the last at

type Store = DocumentationStore<Pick<RootState, 'documentation'>> &
WorkAgreementStore<Pick<RootState, 'workAgreement'>>

The code within the component let's me use the available getters from both with autocompletion, so I'm a bit confused as to what I'm doing wrong. It looks like I have 2 overloads, but the second one looks pretty scoffed. Here's the code in the component for reference and picture's of the issue I'm having.

import {
  defineComponent
} from 'vue'
import {
  useStore
} from "@/store";
import {
  computed
} from "vue";

export default defineComponent({
  data() {
    return {
      store: useStore()
    }
  },

  setup() {
    const store = useStore()

    const thisIsATest = computed(
      () => store.getters.GetAnotherDocumentation
    )
  },
  yetAnotherTest() {
    this.store.commit()
  }
})
`enter code here`

The one with intellisense
The one without intellisense



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source