使用 Vuex 和打字稿的正确方法是什么?

mar*_*lle 22 typescript vue.js vuex

到目前为止,我找到的有关该主题的唯一信息是这篇文章

我正在尝试用 2 个模块实现商店。

export interface RootState {
    /** root state props **/
}

const store: StoreOptions<RootState> = {
    modules: {
        foo,
        bar,
    },
};

export default new Vuex.Store<RootState>(store);
Run Code Online (Sandbox Code Playgroud)

然后我有两个模块:

export interface FooState {
    //(...)    
}

export const foo: Module<FooState, RootState> = {
    //(...)
};

export interface BarState {
    //(...)    
}

export const bar: Module<BarState, RootState> = {
    //(...)
};
Run Code Online (Sandbox Code Playgroud)

一切正常,直到我遇到一种情况,我需要一个来自 foo 模块的 getter 来访问 bar 状态:

export const getters: GetterTree<FooState, RootState> = {
    getInfo: (state, {}, rootState) => number {
        const value = rootState.bar.somevalue;
        //(...)
    },
};
Run Code Online (Sandbox Code Playgroud)

我有一个 linting 错误,说明 rootState 没有 bar 属性。经过一段时间的思考,我设法解决了更改原始 RootState 接口的错误:

export interface RootState {
    /** root state props **/
    foo: FooState;
    bar: BarState;
}
Run Code Online (Sandbox Code Playgroud)

它解决了这个问题,非常适合 IDE 智能感知。

这种方法是否正确?要将所有模块添加到 StoreOptions 使用的 RootState 接口中?

此外,似乎缺乏关于这些类型化接口(StoreOptions、Module、GetterTree 等)的文档:Vuex 是否成熟到可以与 typescript 一起使用?

编辑:我忘了提到:从组件访问商店时,我仍然需要投射 this.$store (但可以使用vuex-class将其最小化)。似乎有一个关于它的问题没有答案。我想到目前为止没有其他解决方案,对吗?

nic*_*idz 24

Vuex 与使用这些 vuex 导入的打字稿完全兼容:

import {GetterTree, MutationTree, ActionTree} from "vuex"
Run Code Online (Sandbox Code Playgroud)

下面的例子展示了在打字稿中使用 vuex 的最简单和最完整的方法。

主存储文件:

import Vue from 'vue'
import Vuex from 'vuex'
import { GetterTree, MutationTree, ActionTree } from "vuex"
import MySubModule from '@/store/submodule'

Vue.use(Vuex)

class State {
    userId: string | null = null;
}

const getters = <GetterTree<State, any>>{
};

const mutations = <MutationTree<State>>{
    setUserId(state, payload) {
        state.userId = payload;
    }
};

const actions = <ActionTree<State, any>>{
    fetchUserId(store) {
    }
};

export default new Vuex.Store({
    state: new State(),
    mutations: mutations,
    actions: actions,
    modules: {
        subModuleName: MySubModule,
        //other submodules
    }
})
Run Code Online (Sandbox Code Playgroud)

子模块存储文件:

import { GetterTree, MutationTree, ActionTree } from "vuex"

class State {
}

const mutations = <MutationTree<State>>{
};

const actions = <ActionTree<State, any>>{
};

const MySubModule = {
    namespaced: true,
    state: new State(),
    mutations: mutations,
    actions: actions
};

export default MySubModule;
Run Code Online (Sandbox Code Playgroud)

希望能帮到你!

  • 这个解决方案甚至不是真正的打字稿,因为它一直使用“any” (6认同)
  • 如果您访问“export default new Vuex.Store({ ... })”提供的导出实例,则此解决方案将不起作用。`store.state.subModule` 抛出错误。 (4认同)
  • 为什么用“any”代替 RootState?正确的不应该是 `GetterTree &lt; State, RootState&gt;` `ActionTree &lt; State, RootState&gt;`?我真的不明白为什么应该是“RootState”,以及不这样做的危险 (4认同)
  • 这个例子是不完整的。您需要展示如何从组件实际使用 Vuex 存储。 (3认同)
  • 右:作为第二个参数的“any”应替换为实际的“rootState”定义,如果没有,则应替换为“Record&lt;string, never&gt;”。另外,可以在“import”行中添加“type”来帮助编译器,如下所示:“import type { GetterTree, MutationTree, ActionTree } from "vuex"” (2认同)