I want to get into Vue3 / Vuex4 using TypeScript but unfortunately the docs didn’t help much
https://next.vuex.vuejs.org/guide/typescript-support.html
As a beginner, I started with a simple issue tracking store module. Inside my issues module I created a index.ts file taking in the “global store instance” and registers itself
import {
ActionContext,
ActionTree,
GetterTree,
MutationTree,
Store,
} from "vuex";
export default (store: Store<{}>): void => {
store.registerModule("issues", {
namespaced: true,
state,
getters,
actions,
mutations,
});
};
export type Issue = {
title: string;
isOpen: boolean;
createdAt: Date;
};
export type State = {
issues: Issue[];
};
export type Getters = {
issues(state: State): Issue[];
};
export type ActionAugments = Omit<ActionContext<State, State>, "commit"> & {
commit<K extends keyof Mutations>(
key: K,
payload: Parameters<Mutations[K]>[1]
): ReturnType<Mutations[K]>;
};
export enum ActionType {
SubmitIssue = "SubmitIssue",
}
export type Actions = {
[ActionType.SubmitIssue](
context: ActionAugments,
submitIssuePayload: SubmitIssuePayload
): void;
};
export type SubmitIssuePayload = {
issueTitle: string;
};
export enum MutationType {
SubmitIssue = "SUBMIT_ISSUE",
}
export type Mutations = {
[MutationType.SubmitIssue](state: State, payload: SubmitIssuePayload): void;
};
const state: State = {
issues: [],
};
const getters: GetterTree<State, State> & Getters = {
issues: function (state: State): Issue[] {
return state.issues;
},
};
const actions: ActionTree<State, State> & Actions = {
[ActionType.SubmitIssue]: function (
{ commit }: ActionAugments,
{ issueTitle }: SubmitIssuePayload
): void {
commit(MutationType.SubmitIssue, { issueTitle });
},
};
const mutations: MutationTree<State> & Mutations = {
[MutationType.SubmitIssue]: function (
state: State,
{ issueTitle }: SubmitIssuePayload
): void {
const issue: Issue = {
title: issueTitle,
isOpen: true,
createdAt: new Date(),
};
state.issues.push(issue);
},
};
Currently I’m stuck with the setup for some reasons:
- I copypasted the
ActionAugments
from Google. Do I really need to reinvent the ActionContext on my own to get access to the commit function? - The setup is not correct yet. The function
store.registerModule
shows this error
.
No overload matches this call.
Overload 1 of 2, '(path: string, module: Module<State, {}>, options?: ModuleOptions | undefined): void', gave the following error.
Type 'GetterTree<State, State> & Getters' is not assignable to type 'GetterTree<State, {}> | undefined'.
Type 'GetterTree<State, State> & Getters' is not assignable to type 'GetterTree<State, {}>'.
'string' index signatures are incompatible.
Type 'Getter<State, State>' is not assignable to type 'Getter<State, {}>'.
Property 'issues' is missing in type '{}' but required in type 'State'.
Overload 2 of 2, '(path: string[], module: Module<State, {}>, options?: ModuleOptions | undefined): void', gave the following error.
Argument of type 'string' is not assignable to parameter of type 'string[]'.ts(2769)
store.ts(26, 3): 'issues' is declared here.
index.d.ts(132, 3): The expected type comes from property 'getters' which is declared here on type 'Module<State, {}>'
which makes sense, because the global store instance is of type Store<{}>
and my module seems to expect Store<State>
How would I fix this?
Thanks for help!
CodePudding user response:
The problem is that module state type was specified in places where root state is expected, while they aren't same.
It's preferable to keep root state type as separate type and import instead of hardcoding it like {}
because it can change with time.
It should be store: Store<RootState>
, GetterTree<State, RootState>
, etc. Where root state generic parameter affects the type of rootState
in Vuex context.