Tim Hutchison
Tim Hutchison

Reputation: 3633

Intellisense for Vuex Store in VS Code

I am building an application using , , and in . I have the extension installed. I have built a definition file to give me intellisense for most of my project, but I haven't been able to figure out how to add my store to intellisense. I've read through the Definition Documentation, but I haven't been able to puzzle together how I might do this. My goal is to be able to get intellisense on anything in this.$store.. Currently, provides intellisense for state, getters, etc. but it does not provide intellisense for the next level (e.g. this.$store.state.TestVariable). How can I get intellisense for my store?

Contract Management Store

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
    state: {
        Contract: new Library.Model.Entity.Contract()
    }
});

Contract Component

<template>
    <contract-line></contract-line>
</template>

<script lang="ts">
    import Vue from 'vue';
    import Vuex from 'vuex';
    import store from '../store/ContractManagementStore';
    import ContractLine from "./ContractLine.vue";

    export default Vue.extend({
        name: 'contract-management',
        store,
        components: {
            'contract-line': ContractLine
        }
    });
</script>

<style>

</style>

Contract Line Component

<template>
    <button v-if="CanDelete"></button>
</template>

<script lang="ts">
    import Vue from 'vue';
    import Vuex from 'vuex';

    Vue.use(Vuex);

    export default Vue.extend({
        computed:{
            CanDelete(): Boolean {
                // Looking for intellisense after this.$store.state.
                return this.$store.state.Contract.ContractStatus.Value === Library.Enums.ContractStatus.Draft
            }
        }
    });
</script>

<style>

</style>

Upvotes: 6

Views: 4855

Answers (2)

kuanyui
kuanyui

Reputation: 781

I also encounter this problem these two days, and cannot bear the lack of the typing-awareness of this.$store.state.

@georg-grab 's solution gives me this inspiration.

  1. I'm not familiar with TypeScript... So this solution may be silly, but it works.
  2. My solution can only deal with this.$store.state, all others such as this.$store.dispatch still has no IntelliSense
// store/index.ts
// I will not explain vuex modules here. Please see the doc of Vuex by yourself.
import Vue from 'vue'
import Vuex, {Store} from 'vuex'

import auth, {State as AuthState} from './modules/auth'  // State is an interface defined in module.

export interface State {
  auth: AuthState
}

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    auth
  }
}) as Store<State>  // Force TypeScript compiler to recognize this as Store<State> instead of Store<any>.

Then add a global instance getter via a Vue plugin:

// main.ts
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store, { State } from './store'

declare module 'vue/types/vue' {  // Tell TypeScript the type of this.$state is our defined 'State'
  interface Vue {
    $state: State
  }
}
const TypedState = {  // define a Vue plugin. See https://vuejs.org/v2/guide/plugins.html
  install(Vue: any) {  // For simplify, didn't pass 'State' via options
    Object.defineProperty(Vue.prototype, '$state', {  // Add a global getter 'this.$state' in vm
      get (): State { return store.state as State }  // Force TypeScript compiler to recognize this as our defined 'State'
    })
  }
}
Vue.use(TypedState)

Now you can access the values in this.$store.state via this.$state, with IntelliSense.

I also want to "overwrite" the interface of vm.$store (from Store<any> to Store<State>), but TypeScript seems to has no way to do such thing:

declare module 'vue/types/vue' {
  interface Vue {
    $store: Store<State>   // Error
  }
}

Upvotes: 0

Georg Grab
Georg Grab

Reputation: 2301

You could achieve this by explicitly typing your state.

In Contract Management Store.ts

export interface ContractManagementState {
    Contract: ContractType;
}

In your Component:

...
(this.$store as Store<ContractManagementState>).<intellisense here>

You have to do this every time you access the state this way, unfortunately. This is due to the way Vuex uses module augmentation in order to declare the existence of the $store property to typescript.

In vuex/types/vue.d.ts:

declare module "vue/types/vue" {
  interface Vue {
    $store: Store<any>;
  }
}

You cannot override the any with your concrete state typings (this is called module augmentation after all). A possible solution is to use getters for accessing your Store. Several typescript libraries exist for adding type information to getters, mutators, and actions, such as vuex-typescript and vuex-typex.

Upvotes: 1

Related Questions