📦src
┣ 📂store
┃ ┣ 📂modules
┃ ┃ ┗ 📂generic_module
┃ ┃ ┃ ┣ 📜actions.ts
┃ ┃ ┃ ┣ 📜getters.ts
┃ ┃ ┃ ┣ 📜index.ts
┃ ┃ ┃ ┗ 📜mutations.ts
┃ ┗ 📜index.ts > *root_index.ts*
Last active
April 6, 2022 13:32
-
-
Save luna-koury/ad3e2a2a62533aa590784a0eff2bef17 to your computer and use it in GitHub Desktop.
Vuex 4 - Boilerplate Typescript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ActionContext, ActionTree } from "vuex"; | |
import { Mutations, MutationTypes } from "./mutations"; | |
import { State } from "./index"; | |
import { RootState } from "@/store"; | |
//(C) - Ações | |
// [C.1] inserir a definição da ação x no enum | |
// ==> { setX = "NOMEMODULO__SET_ X" } | |
export enum ActionTypes { | |
setValue = "GENERIC__SET_VALUE", | |
} | |
// !!! AUGUMENTED ACTION CONTEXT !!! | |
type AugmentedActionContext = { | |
commit<K extends keyof Mutations>( | |
key: K, | |
payload: Parameters<Mutations[K]>[1] | |
): ReturnType<Mutations[K]>; | |
} & Omit<ActionContext<State, RootState>, "commit">; | |
// [C.2] definir o tipo da ação setX | |
// ==> [ActionTypes.setX]( | |
// ==> { commit }: AugmentedActionContext, | |
// ==> payload: TIPO_DE_X | |
// ==> ): void; | |
export interface Actions { | |
[ActionTypes.setValue]( | |
{ commit }: AugmentedActionContext, | |
payload: any | |
): void; | |
} | |
// [C.3] declara a ação setX | |
// [ActionTypes.setX]({ commit }, payload) { | |
// commit(MutationTypes.X, payload); | |
// }, | |
export const actions: ActionTree<State, RootState> & Actions = { | |
[ActionTypes.setValue]({ commit }, payload) { | |
commit(MutationTypes.VALUE, payload); | |
}, | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<input type="text" name="test" id="test" v-model="data" /> | |
</template> | |
<script lang="ts"> | |
import { defineComponent, ref } from "vue"; | |
import useStore from "path/to/store/index"; | |
import { ActionTypes as ModuleA } from "path/to/module/index"; | |
export default defineComponent({ | |
name: "name", | |
components: {}, | |
props: {}, | |
setup() { | |
const data = ref(""); | |
// declare useStore inside composition API setup() | |
const store = useStore(); | |
// this will be acording with the module's action.ts | |
store.dispatch(ModuleA.setData, data.value); | |
// this will be acording with the module's getters.ts | |
console.log(store.getters.data); | |
return { data }; | |
}, | |
}); | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { GetterTree } from "vuex"; | |
import { State } from "./index"; | |
import { RootState } from "@/store"; | |
// (D) - Getters | |
// [D.1] - Define o tipo do getter x | |
// => x(state: S): TIPO_DE_X; | |
export type Getters<S = State> = { | |
value(state: S): any; | |
}; | |
// [D.2] - Declara o getter x | |
// => x: (state) => { | |
// => return state.x; | |
// => }, | |
export const getters: GetterTree<State, RootState> & Getters = { | |
value: (state) => { | |
return state.value; | |
}, | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { getters, Getters } from "./getters"; | |
import { mutations, Mutations } from "./mutations"; | |
import { actions, Actions, ActionTypes } from "./actions"; | |
import { | |
Store as VuexStore, | |
Module, | |
CommitOptions, | |
DispatchOptions, | |
} from "vuex"; | |
import { RootState } from "@/store"; | |
// PARA ALTERAR A STORE | |
// (A) - Alterar o state ./ | |
// (B) - Alterar as mutações ./mutations.ts | |
// (C) - Alterar as ações ./actions.ts | |
// (D) - Alterar os getters ./getters.ts | |
// !!! não mecher nos snipets de código com comentário em maiusculo !!! | |
//[A.1] inclui valor na interface do state | |
// ==> x: TIPO_DE_X | |
interface State { | |
value: any; | |
} | |
//[A.2] declara o valor no objeto do state | |
// ==> x: VALOR_DE_X | |
const state: State = { | |
value: "", | |
}; | |
const generic_module: Module<State, RootState> = { | |
state, | |
mutations, | |
actions, | |
getters, | |
}; | |
export { State, ActionTypes, Store }; | |
export default generic_module; | |
// !!! CONFIGURA TIPAGEM DA STORE !!! | |
type Store<S = State> = Omit< | |
VuexStore<S>, | |
"commit" | "getters" | "dispatch" | |
> & { | |
commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>( | |
key: K, | |
payload: P, | |
options?: CommitOptions | |
): ReturnType<Mutations[K]>; | |
} & { | |
getters: { | |
[K in keyof Getters]: ReturnType<Getters[K]>; | |
}; | |
} & { | |
dispatch<K extends keyof Actions>( | |
key: K, | |
payload: Parameters<Actions[K]>[1], | |
options?: DispatchOptions | |
): ReturnType<Actions[K]>; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// this should be in your main.ts file | |
import { store, key } from "path/to/store/index"; | |
const app = createApp(App); | |
app.use(store, key); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { MutationTree } from "vuex"; | |
import { State } from "./index"; | |
// (B) - Mutações | |
// [B.1] inserir a definição da mutação X no enum | |
// ==> { X = "SET_ X" } | |
export enum MutationTypes { | |
VALUE = "SET_VALUE", | |
} | |
// [B.2] definir o tipo da mutação X | |
// ==> [MutationTypes.X](state: S, payload: TIPO_DE_X): void; | |
export type Mutations<S = State> = { | |
[MutationTypes.VALUE](state: S, payload: any): void; | |
}; | |
// [B.3] declarar a mutação X | |
// ==> [MutationTypes.X](state, payload) { | |
// ==> state.x = payload; | |
// ==> }, | |
export const mutations: MutationTree<State> & Mutations = { | |
[MutationTypes.VALUE](state, payload) { | |
state.value = payload; | |
}, | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { InjectionKey } from "vue"; | |
import { | |
createStore, | |
Store as VuexStore, | |
useStore as baseUseStore, | |
} from "vuex"; | |
import generic, { | |
State as GenericState, | |
Store as GenericStore, | |
} from "./modules/__generic_module"; | |
import other, { | |
State as OtherState, | |
Store as OtherStore, | |
} from "./modules/other_module"; | |
// define tipos pro state da store | |
export interface RootState { | |
debitos: GenericState; | |
/* other: OtherState; */ | |
} | |
export type RootStore = GenericStore<Pick<RootState, "debitos">>; | |
// & OtherStore<Pick<RootState, "other">> & | |
// define injection key | |
export const key: InjectionKey<VuexStore<RootState>> = Symbol(); | |
export const store = createStore<RootState>({ | |
modules: { | |
generic, | |
// other | |
}, | |
}); | |
// o usar `import useStore from '@store'` | |
export default function useStore(): RootStore { | |
return baseUseStore(key); | |
} |
I'd like to mention there is a typo on the component.vue gist, if I'm not mistaken.
I believe it should be setValue:
store.dispatch(ModuleA.setValue, data.value);
Instead of setData:
store.dispatch(ModuleA.setData, data.value);
Hello, I am using vuex in the same way as above. If namespaced is not used, the state and action of the same variable method is impossible, so the value of namespaced is used as true. Can't I use the above method when using namespaced??
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, thanks for asking, a basic implementation is indeed very important. I realize now this should be a repo, things are starting to look messy.
Well, there's some setup to be made onto your main.ts. I've put the code required (only for vuex) here.
The component implementation is here. Note that both the store hook and the ActionTypes need to be imported (multiple ActionTypes if working with multiple modules), and while the
store.getters.x
can access any declared module getter, sadly it cannot access the module itself (eg.store.getters.moduleA.data
).This implementation of typed Vuex 4 is not cool, very hard to do, a little easier to maintain, and somewhat comfortable to use, but hopefully, someone will add official typed composition API support soon, i'd try and do it but I'm not yet super familiar with vue3 inner workings.
As for your warning, I can imagine it involves the store injection key, but if the correct implementation does not solve it i don't know what can be done. As, although i have used it, i do not completely understand its core concepts yet.
Sorry if it's a little hard to understand. I'm not fluent in english.