如何正确使用Vuex和打字稿?

时间:2018-12-16 23:11:27

标签: typescript vue.js vuex

到目前为止,我发现的有关该主题的唯一信息就是这个article

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

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

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

export default new Vuex.Store<RootState>(store);

然后我同时拥有两个模块:

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

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

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

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

一切正常,直到出现一种情况,我需要从foo模块中获取吸气剂以访问条形状态:

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

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

export interface RootState {
    /** root state props **/
    foo: FooState;
    bar: BarState;
}

它解决了问题,对IDE智能感知非常有用。

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

而且,似乎似乎缺少有关这些类型化接口(StoreOptions,Module,GetterTree等)的文档:Vuex是否足够成熟,可以与打字稿一起使用?

编辑:我忘了提及:从组件访问存储时,我仍然需要转换this。$ store(但是可以用vuex-class最小化)。似乎有一个question未解决。我想到现在还没有其他解决方案,对吗?

2 个答案:

答案 0 :(得分:1)

使用这些vuex导入,Vuex与Typescript完全兼容:

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

下面的示例显示了在打字稿中使用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
    }
})

SubModule存储文件:

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;

希望能帮助您!

答案 1 :(得分:0)

我最终使用了空的rootState接口并动态添加了所有模块。它根本消除了跨模块通信的问题。让我解释一下。 我来自C#,所以我想消除字符串文字和动态类型。我是用vuex-typex做的。请注意,它是模块,因此您可以使用许多自定义内容,例如事件或帮助函数。这是我的简化示例:

import { getStoreBuilder, BareActionContext } from "vuex-typex";
import { LiteEvent } from "./utility/LiteEvent";
import { IRootState } from "../store";
import ModuleApi, { IBuildInfo } from "./ModuleApi";

export interface IModuleState {
  builds: IBuildInfo[];
}

const moduleBuilder = getStoreBuilder<IRootState>().module<IModuleState >("branches", { builds: [] });

const buildsChanged: LiteEvent<void> = new LiteEvent<void>();

const ModuleStore = {
  get state(): IModuleState { return stateGetter(); },
  get lastBuildInfo(): IBuildInfo | null { return lastBuildInfoGetter(); },

  // mutations
  setBuilds: moduleBuilder.commit(setBuilds),

  // actions
  requestBuilds: moduleBuilder.dispatch(requestBuilds),

  buildsChanged: buildsChanged.expose(),
};
export default ModuleStore;

// getters
const stateGetter = moduleBuilder.state();

const lastBuildInfoGetter = moduleBuilder.read(lastBuildInfo);
function lastBuildInfo(state: IBranchesState): IBuildInfo | null {
  const len = state.builds.length;
  return len > 0 ? state.builds[state.builds.length - 1] : null;
}

// mutations
function setBuilds(state: IBranchesState, payload: { newBuilds: IBuildInfo[] }): void {
  state.builds = payload.newBuilds;
  onBuildsChanged.trigger();
}

type ActionContext = BareActionContext<IModuleState, IRootState>;

// actions
async function requestBuilds({ state }: ActionContext): Promise<void> {
  const builds = await RepoBrancesApi.getBuilds(state.currentBranch);
  BranchesStore.setBuilds({ newBuilds: builds});
}

getStoreBuilder<IRootState>().registerModule(moduleBuilder.namespace);

如果您对LiteEvent感兴趣-敬上Jason Kleban's post

这是另一个vuex模块或其他地方的用法:

async function requestSelectedChartGeom(context: ActionContext, payload: { chartName: string }): Promise<void> {
  const chartGeom = await ChartBoundApi.getBoundsForChart(ModuleStore.lastBuildInfo, payload.chartName);

  ...
}

ModuleStore.onBuildsChanged.on(s => {
  CommitLogStore.requestCommits();
});

我不喜欢太多的存储模块代码(由于工作函数不能是匿名的,因此必须将getter / mutation / action定义与工作函数分开),但是没有动态类型和字符串文字,所以我很高兴