Reputation: 564
I followed this tutorial to set up a Vuex store with modules using TypeScript.
So far I have:
vuex/types.ts:
export interface RootState {
version: string;
}
vuex/user-profile.ts:
import { ActionTree, Module, MutationTree } from 'vuex';
import { RootState } from './types';
interface User {
firstName: string;
uid: string;
}
interface ProfileState {
user?: User;
authed: boolean;
}
const state: ProfileState = {
user: undefined,
authed: false,
};
const namespaced: boolean = true;
export const UserProfile: Module<ProfileState, RootState> = {
namespaced,
state,
};
store.ts:
import Vue from 'vue';
import Vuex, { StoreOptions } from 'vuex';
import { UserProfile } from '@/vuex/user-profile';
import { RootState } from '@/vuex/types';
Vue.use(Vuex);
const store: StoreOptions<RootState> = {
state: {
version: '1.0.0',
},
modules: {
UserProfile,
},
};
export default new Vuex.Store<RootState>(store);
In my router.ts I want to access the authed
state of the store like this:
import store from './store';
//...other imports...
const router = new Router({
//... route definitions...
});
router.beforeEach((to, from, next) => {
const isAuthed = store.state.UserProfile.authed;
if (to.name !== 'login' && !isAuthed) {
next({ name: 'login' });
} else {
next();
}
});
The code works (the app redirects properly), HOWEVER, the compiler throws errors saying Property 'UserProfile' does not exist on type 'RootState'
, which makes sense since it's not defined, but should it not look under the modules as well, or did I not define the module correctly?
Upvotes: 12
Views: 4764
Reputation: 167
You need to define all stores to rootState interface like this:
export default interface RootState {
version: string,
UserProfile: any
}
You could also import the interface from the UserProfile and use instead of any. Since you dont use pascal casing for your file names
This will tell the rootState to expect a vuex store called UserProfile with any type or UserProfile interface.
I have a rootstate interface for my vuex store like this:
export default interface RootState {
version: string,
config: any,
cart: any,
checkout: any,
cms: any,
product: any,
shipping: any,
user: any,
wishlist: any,
attribute: any,
ui: any,
newsletter: any,
category: {
current_path: string,
current_product_query: any,
current: {
slug: string,
name: string
},
filters: any
}
}
Upvotes: 1
Reputation: 1
I would recommend doing a double cast. One to any and one back to what you actually want. Remember that in the last router.ts file below, "store" is an instance of the Store and the other two imports are just types.
I have omitted the namespaced, state, getters, actions, mutations code for brevity. They are simply object structures
store/myModule/types.ts:
export default interface State {
testValue
}
store/myModule/index.ts:
import RootState from '../types'
const module: Module<State, RootState> = {
namespaced,
state,
getters,
actions,
mutations,
}
export default module
store/types.ts:
interface RootState {
myOtherTestValue: string
}
export default RootState
export { RootState }
store/index.ts:
import RootState from './types'
import myModule from './myModule'
export const cmStore: StoreOptions<RootState> = {
actions,
mutations,
state,
modules: {
myModule,
},
plugins,
}
export default new Vuex.Store<RootState>(cmStore)
in router.ts:
import store from './store'
import RootState from './store/types'
import MyModuleState from './store/myModule/types'
// to get what you want typed how you want:
const myState = ((store.state as any).myModule as MyModuleState)
console.log(myState.testValue)
Upvotes: -1
Reputation: 1426
This is a working solution with dependecies "vuex": "^4.0.2"
, "vue-router": "^4.0.10"
and "vue": "^3.1.4"
.
Import the store
into your router
file to access your state in the module:
import store from "@/store/store";
In my case the modules name is authModule
and I access the state
of token
, where a jwt is stored:
let loggedIn = store.state.authModule.token;
Upvotes: -1
Reputation: 7
1
const isAuthed = store.state["UserProfile"].authed; // false
2
const state:any|State = store.state
const isAuthed = state.UserProfile.authed; // false
3
const isAuthed = (<any|State>store.state).UserProfile.authed; // false
Upvotes: -1
Reputation: 1185
EDIT: It seems that direct access to state is the issue here. Line
const isAuthed = store.state.UserProfile.authed;
I believe this happens because it's namespaced. The solution would be to create a getter.
const getters: GetterTree<ProfileState, RootState> = {
user(state): User {
return state.user
}
};
And then you can access it like
store.getters['UserProfile/user']
Also, please consider using getters for accessing your state data. See Getters for reference.
Upvotes: -1