I have the following Vuex module using Typescript that I'm exporting from a library:
import * as types from '@/store/types';
import {Formio} from 'formiojs';
import { VuexModule, Module, Mutation, Action } from 'vuex-module-decorators'
interface RoleItem {
_id: string;
title: String;
admin: Boolean;
default: Boolean;
}
interface RoleList {
[key: string]: RoleItem;
}
export class Auth extends VuexModule {
public user: {}
public loggedIn: boolean
public roles: {}
public forms: {}
public userRoles: {}
@Action
setUser({ state, commit, dispatch }, user) {
commit(types.SET_USER, user);
dispatch('setLoggedIn', true);
dispatch('setUserRoles', state.roles);
}
@Action
setLoggedIn({commit}, loggedIn) {
commit(types.SET_LOGGED_IN, loggedIn);
}
@Action
getAccess({ commit, dispatch, getters }) {
const projectUrl = Formio.getProjectUrl();
Formio.request(projectUrl + '/access')
.then(function(accessItems) {
commit(types.SET_ROLES, accessItems.roles);
commit(types.SET_FORMS, accessItems.forms);
if (getters.getLoggedIn) {
dispatch('setUserRoles', accessItems.roles);
}
});
}
@Action
setUserRoles({ commit, getters }, roles: RoleList) {
const roleEntries = Object.entries(roles);
const userRoles = getters.getUser.roles;
const newRolesObj = {};
roleEntries.forEach((role) => {
const roleData = role[1];
const key = 'is' + role[1].title.replace(/\s/g, '');
newRolesObj[key] = !!userRoles.some(ur => roleData._id === ur);
});
commit(types.SET_USER_ROLES, newRolesObj);
}
@Mutation
[types.SET_USER](user) {
this.user = user;
}
@Mutation
[types.SET_LOGGED_IN](loggedIn: boolean) {
this.loggedIn = loggedIn;
}
@Mutation
[types.SET_ROLES](roles: RoleList) {
this.roles = roles;
}
@Mutation
[types.SET_FORMS](forms) {
this.forms = forms;
}
@Mutation
[types.SET_USER_ROLES](userRoles) {
this.userRoles = userRoles;
}
}
export default Auth;
I want to simply import it it in the parent vue app as a namespaced Vuex module and add it to my store as a new module:
import Vue from 'vue';
import Vuex from 'vuex';
import { Auth } from 'vue-formio'
Vue.use(Vuex);
...
resourceModules.auth = Auth;
export default new Vuex.Store({
modules: resourceModules,
strict: debug,
});
That part all works fine. The problem is setting the namespaced: true
and name:auth
properties in the exported store. From what I've read , I should be able to do it with the @Module
decorator like this:
@Module({ namespaced: true, name: 'auth' })
export class Auth extends VuexModule {
However, as soon as I add the parentheses after the @Module
decorator, I get this TS error in my IDE:
TS1238: Unable to resolve signature of class decorator when called as an expression. Cannot invoke an expression whose type lacks a call signature. Type 'void' has no compatible call signatures.
As seen in the vuex-module-decorators code, these are allowed options:
export interface StaticModuleOptions {
/**
* name of module, if being namespaced
*/
name?: string;
/**
* whether or not the module is namespaced
*/
namespaced?: boolean;
/**
* Whether to generate a plain state object, or a state factory for the module
*/
stateFactory?: boolean;
}
This is my first foray into Typescript, so I'm stumped. I'm still researching, but in the meantime, how do I add the namespacing to this Vuex module with Typescript?
A quickfix I figured out is to add
import { ModuleOptions } from 'vuex-module-decorators/dist/types/moduleoptions';
@Module({ dynamic: true, name: 'user', namespaced: true, store: Store } as ModuleOptions)
to the configuration object.
The error is because you're calling @Action
s with params it doesn't understand. Docs here .
Probably the most confusing part of using vuex-module-operators
is the fact that, unlike in normal Vuex, the first param (the ActionContext) of @Action
s is skipped. It is available as this.context
.
Here's how one of your actions would work with this package:
@/store/auth.ts
import { ActionContext } from 'vuex';
import { Module, VuexModule, Action } from 'vuex-module-decorators';
import * as types from './types';
import store from '.';
@Module({ namespaced: true, store, name: 'auth' })
export default class AuthStore extends VuexModule {
@Action
async setUser(user) {
const { state, commit, dispatch } = this.context;
commit(types.SET_USER, user);
dispatch('setLoggedIn', true);
dispatch('setUserRoles', state.roles); // could be `this.roles`
}
}
Make sure you also call getModule(Auth, store)
in your main store file, after creating the store. I believe this call has no other effect than inferring types. (the store seems to work fine without it, but Typescript no longer works). Example:
@/store/index.ts
import Vue from 'vue';
import Vuex from 'vuex';
import Auth from './auth';
import { getModule } from 'vuex-module-decorators';
Vue.use(Vuex);
const store = new Vuex.Store({
//...
modules: {
auth: Auth
}
});
getModule(Auth, store);
export default store;
As a side note, I don't fully understand why you're dispatching setUserRoles
with state.roles
- state
is available in setUserRoles
action just like it's available in setUser
action, so no need to send the roles as param.
Did you mean dispatch('setUserRoles', user.roles);
?
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.