
Preface
🚨 The approach, described in this article, is not encouraged to be used in production, till Vuex 4.x and Vue.js 3.x are complet...
For further actions, you may consider blocking this person and/or reporting abuse
Wow! I totally didn't expect that this article will be popular. Thank you for your comments.
According to the comments I've read, here is what I'm planning to include:
namespaced
modules;What do you think of idea of creating a dedicated package with helper types (
MutationTree
,GetterTree
,ActionTree
,Store
)?I also managed to type
getters
,rootState
,rootGetters
inactions
andgetters
.Stay tuned.
Hey Andrew, thanks for this great example. I am currently stuck in the process of typing getters, rootState, and rootGetters in actions and getters. Any chance that you can share an example? I guess the AugmentedActionContext and Store type definitions is what I am looking for.
Thank You
As a reference, I've uploaded a gist here: gist.github.com/soerenmartius/5f69...
The code works but typescript is unable to resolve the getters properly. Any help will be highly appreciated
Thank you very march for great article!
You promice to add some new code as you described above.
May be you have any news about it ?
Hey Andrew, any thoughts on the namespaced modules yet? Great guide otherwise!
Hey Sergej, Thanks. You have to manually create
MODULE_NAME/MUTATION_TYPE
mappings by now. But if you are using TS4.1
you can use Template Literal Types.Here is the snippet from the helper library I am developing right now:
I see, nice trick, thanks, Andrew!
Hi @3vilarthas
Did you share the update avoid the Types for rootState? I would like to see this resource. Thanks in advance!
Hey Andrew, thanks for this great example.
can you please help with namespaced modules in vuex4 with typescript
I'm using your suggested way but I'm still getting the error
type Namespaced = {
[P in keyof T & string as
${N}/${P}
]: T[P]}
type NamespacedMutations = Namespaced
Hi, Harsh. I tried your method, but I still cannot use
store.dispatch('moduleName/actionName'), is there any fixes..
Yes I solved, This is the solution you can refer
If you want a complete boilerplate with vue3 and other more configs you can clone or fork my repository.
github.com/techarshgupta/vue3-boil...
Thank you!
I tried this method but seems like it will disable type check when I use
store.dispatch('moduleName/actionName') because I can pass any string and the compiler can compile successfully
type Namespaced = {
};
type NamespacedActions = Namespaced;
no, it will give an error when you compile you can check my repo that I mentioned.
I am still disappointed with how difficult Vuex+Typescript is to set up. I will keep using module-decorators (github.com/championswimmer/vuex-mo...) which let you have complete type safety and no redundancy in your code:
And then just use it in a component with:
Thanks you so much for this amazing start-point!
I wanted to evaluate the viability of Vuex + Typescript when compared to my known Redux + Typescript, as I'm not too happy with Redux. But as I have never used Vue nor Vuex in production before, bringing everything together is pretty challenging.
I'm quite decent in Typescript along though, and I noticed a few things regarding its usage where I would do things slightly different, so I thought I would write them here so you can either explain why you deem them necessary or maybe learn a tiny bit from a thankful reader:
I noticed a number of duplic typing. I.e. in src/store/mutations.ts you define the SET_COUNTER parameters typeonce in the static type (as you have to if you define the type statically), and once in the actual implementation. You could get rid of the type in the implementation, it would still be types, just as the state field is.
while we're there, why did you add the
MutationTree<State>
annotation? If you happend to define a mutation with the wrong type you would at the latest get warned in thecreateStore
function, I would think at least. Additionally if you get rid of that annotation you could also ease typing by implicitly inferring the type with typeof.Honestly, I never use the Enum type in Typescript again since I found the Union of string literals (
"OPTION_1" | "OPTION_2"
). Overall the purpose of these Enums in Vuex (and i.e. Redux too) is a moot point IF you have typed everything correctly all the way through. I personally do not declare enums for the different Actions/Mutations, just identifying by the function name is more than sufficient.I would prefer to declare the type of Store in the
.d.ts
fileSo, I was applying all the wisdom in here, to my quite large vuex stack, and IÂ stumbled upon the second argument of Getters (I leave the third and fourth to the reader)
Basically, the second argument to Getters references the Getters for the current namespace, but not as functions, as values directly.
For example, I have this:
The problem is that the getters argument as an "any" type everywhere, IÂ tried to put the
Getters
type, but that was not right. After a bit of fiddeling around (I am still a bit new and rough in typescript)Â IÂ ended up having this :The naming is probably awful, and now that I think about it, one should just have to generate a
Getters
that is, say,user: PayloadUser; roles:Â string[];
and a different kind of fiddeling be done so that the type with the function definitions can be generated automatically.Also, if all this goes into a module somewhere, this should probably get there too.
So, I thought about what I wrote in the end and changed my code, it now reads:
Not sure about it, but I think you have a typo:
Shouldn't this be
store.ts
orindex.ts
?Anyways. Thank you for this short explanation on how to type the new vuex store 🦄🎉🥳
Thanks! Fixed.
Thank you! It's vary nice article! However, how to apply it in
mapState, mapGetters, mapMutations, mapActions
?Great question
actually, I have a question, according to this line
payload: Parameters[1]
it forces me to commit a mutation with payload, but what if I just want to commit a mutation without a payload?
like the RESET_COUNTER action in your article
I have same problem. Did you have the solution?
You can mark the
payload
parameter as optional.I see you are using type intersection for example
GetterTree<State, State> & Getters
. I have a general dbt, why did you choose this way but not interfaces.In interfaced you in extend the
GetterTree<State, State>
and then use it in the Getters part.Thank you for this, is a great post and got me started, thanks!
For anybody who is implementing this with Modules, I'm not a Typescript expert at all, but i got it working, I'm not 100% sure I did it in the best way but it is working as expected for me. You can find an example of my implementation here:
gist.github.com/javisperez/b13d020...
Open to suggestions or questions, I hope this helps somebody.
I'm going to include a section about
namespaced
modules soon.Great article!
Just a note that you have a spelling mistake
GET_COUTNER
rather thanGET_COUNTER
Thanks for this article Andrew! Could you please review the quirks that remains to be solved with my example repo (based on examples by you and others), in this SO question I've made yesterday: stackoverflow.com/questions/640805...
thanks you, it was really helpful!
how would you apply this while using namespaced modules?
I'm going to include a section about namespaced modules soon.
Nice article, been playing with TS + Vue3 + Vuex4 recently.
Just a question : how would define the type for Getters to should support arguments ?
Thanks
Thanks, I'll include it too.
Hey Andrew, great article, can i translate into chinese to release to china forum?
I will mark your nickname and origin link in the article.
Great post. I’m curious that everything you did is just TypeScript things except defining global $store type, so isn’t possible to do the same in Vue 2 + Vuex 3 and have a fully typed store?
What we did in our project is that we just removed the global
vuex
types/vue.d.ts
files, and used the approach with Vue2.x
. Take a look at npm-patch-package. Then you can just comment out these lines and apply the patch. That's it, you can type the store in2.x
.I also like the idea that API and code stay the same, we just enhance typings.
Better than most of typescript vuex classes and accessors out there tbh
great article!
I'm highly recommend vuex binding helpers for more clean code with vuex + TS :
github.com/ktsn/vuex-class
Update from March 2021: I'd be careful about using this lib, new friends! It's pretty old, and after trying to use it lightly, I'd say it may or may not break projects using the latest Vue (composition) + TypeScript + Vuex packages!
Hey guys, amazing post, i have only one question, how can i access a specific module state in another, Thank you in advance.