Open Anonyfox opened 7 years ago
Any official news on how this will probably be implemented on Vuex 4?
Seems that vuex-module-decorators is the most well-maintained workaround for now, but I'd like to at least know if the official solution will be somewhat similar to that one / vuex-simple (class-based store definition), or vuex-context / vuex-type-helper (object-based store with generated typed helpers).
That way me and my team can more easily migrate to Vue 3 / Vuex 4 in the future.
Thank you in advance
I also started working on yet another library for writing ES6/typescript classes as vuex modules without having to use decorators but with full type completion support. Also it is possible to write mutators (which I hope will be removed in vuex 4) as ES6 setter functions: vuex-typesafe-class.
I hope vuex 4 will be close to that (except the need to use mutators).
I'm also starting on a fairly large Vue/Vuex typescript app. I'm trying to figure out best practices for dir layout and module structure. I think this makes sense:
store/
store.ts
store-types.ts
moduleA.ts
moduleA-types.ts
but if I'm going to have submodules, maybe deeper nesting is best:
store/
store.ts
store-types.ts
moduleA/
moduleA.ts
moduleA-types.ts
subA/
subA.ts
subA-types.ts
moduleB/
moduleB.ts
moduleB-types.ts
(I don't like lots of files named 'index.ts'; they all look the same. I prefer files to be named for what they are.)
So does this latter structure look good? It seems like you do need a foo-types.ts for each module so the Vue components can import the module's shape, right? (I suppose you could put all types in store/store-types.ts
though -- they don't create any Javascript output, right?)
It does seem overly deeply nested to me; I don't like adding extra dir layers unless needed.
Is there a "best practices" document on how to do this?
I tackled it here - with no additional code, just better typing:
https://github.com/ClickerMonkey/vuex-typescript-interface
I started where @danielfigueiredo did, but figured out I could automatically detect getters, mutations, and actions all from one interface.
So now state, getters, commit, and dispatch all require valid strings and types or TS will throw an error. If you also have state/getters/actions/mutations defined on your interface and NOT in your store it will throw an error. The getter/mutation/action definitions passed in as options must have the proper types or it will also throw an error here as well!
Hi All,
Super interesting comments. Thank you all !
If I can ask ... (we're now October 2019 and we're all using Vue 3) ... Any official news on this subject ? In other words ... What's the proper way to implement Vuex Typescript in a Vue 3 Project ?
Regards, Johnny
I don't know about Vue 3 (I'm waiting for the official release) but I do have a reasonably clean, complete Typescript-typesafe vuex-module-decorators example at https://github.com/garyo/vuex-module-decorators-example.git if you're interested.
I found a solution for the code that uses the store and calls dispatch
, commit
, getters
and the state
. For example:
store.dispatch("myModule/myAction", myPayload);
… is replaced by a wrapper:
store.dispatch.myModule.myAction(myPayload);
… which is fully typed.
this worked for me:
// in vuexCommitFuncVars.ts
export default {
decreaseCount: "decreaseCount",
...
};
// in actions.ts
import funcVars from "./vuexCommitFuncVars";
commit(funcVars.decreaseCount);
// before i had to write 'commit("decreaseCount")'
// in mutations.ts
[funcVars.decreaseCount](state) {
state.count= state.count- 1;
},
Any official news in 2020?
IIRC, vue next (aka vue 3) is on an alpha release, we still need to wait for the official vue ecosystem to update, and in the future this will (most probably) entirely handled natively by vuex.
Please correct me if I’m wrong.
@AlenQi I'm using Vue 2 and Vuex with TS without any problems. Here you can see how I use it: https://github.com/MikeMitterer/vuetify-ts-starter/blob/master/src/views/About.vue (CounterStore) And here https://github.com/MikeMitterer/vuetify-ts-starter/tree/master/src/store how everything is glued together. Hope this helps.
So I made a small library wich allows you to get fully typed store in actions and components.
It also adds helpers that allow you to import rather than us mapXXX
or decorators
For me adding the store state type in module declaration is enough to have auto-completion
declare module "vue/types/vue" {
interface Vue {
$store: Store<RootState| any>;
}
}
A more complete exemple :
import Vue from "vue"
import Vuex, { StoreOptions} from "vuex"
import App from './App.vue'
Vue.use(Vuex)
interface RootState {
user: App.Models.User | null;
notifications: App.Models.Notification[];
}
const store: StoreOptions<RootState> = {
state: {
user: null,
notifications: []
},
mutations: {
login(state, user: User) {
state.user = user
},
logout(state) {
state.user = null
}
},
actions: {
},
modules: {
}
}
store = new Vuex.Store<RootState>(store);
declare module "vue/types/vue" {
interface Vue {
// https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html#use-union-types
// eslint-disable-next-line @typescript-eslint/no-explicit-any
$store: Store<RootState| any>;
}
}
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
The can't overwrite Store<any>
issue (originally tracked in #994) will be resolved in Vuex 4 - beta version release notes here
Vuex has created a lot of pain for Typescript users. Now that we have the Composition API... do we even really need Vuex? In 2020, if I'm training a team to use Vue 3, why would I teach them Vuex? Creating stateful singletons that you can compose is a really nice pattern. Code is so much cleaner without Vuex.
The arguments in favor of Vuex (in my mind) are:
What am I missing?
Vuex has created a lot of pain for Typescript users. Now that we have the Composition API... do we even really need Vuex? In 2020, if I'm training a team to use Vue 3, why would I teach them Vuex? Creating stateful singletons that you can compose is a really nice pattern. Code is so much cleaner without Vuex.
The arguments in favor of Vuex (in my mind) are:
- Vue devTools integration (time travel, etc.)
- Slightly easier to avoid name collisions with namespace modules?
What am I missing?
Agree, I've trained my teammate to use Vue's injection to provide shared data between components.
This is true, but Vue dev tools integration is not a small thing. It can be extremely useful for debugging.
I'm kinda facing the same issue here, this is how my actions.ts
looks like:
export default {
updateIp(context: any, ip: string) {
context.commit('setIp', ip);
}
}
But I get this warning:
2:21 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
Any idea how to fix this?
A shout out to @paleo, direct-vuex is fantastic. Strongly typed coding within the store and (perhaps more importantly) when components access the store state and actions.
I tried Vuex 4 today, but it didn't really do much for me (I'm still on Vue2 + Composition add-on). Is there an outline of how Vuex 4 will work for Typescript users? All I could find was an old roadmap with generic statements about "supporting Typescript"
@rfox12 As far as I know, you'll need to wait for Vuex 5. Vuex 4 was focused on preparing for Vue 3 and allowing passing your own interface to Store<>
Before Vuex 4, you'd have to do:
new Vue({
store: new Store(store) as Store<any>
})
thus this.$store.state wouldn't be typed. Working around that (passing your own store interface instead of any) required some trickery
I'll add two additional compelling reasons to keep Vuex in Composition API world:
So in short... I'm keeping Vuex for large projects, but I have an question. First some background. To get typescript support today I find it best to import store from './store';
and then use something like store.dispatch.core.signOut()
(with direct-vuex). Inside my single-page components. This is instead of using this.$store
(which I cannot get Typescript to understand yet--still on Vuex 3). My question is: is there anything magical about Vue's instance of the store that I should be aware of? Any wrapping or logic that would make this.$store
different from the imported version?
@rfox12 You should always use this.$store
if you're doing SSR. Otherwise, it doesn't matter.
The difference with direct import is that when you use this.$store
, you're using the store instance injected into the Vue instance. When doing SSR, at server side, if you use direct import, the store instance will be shared between the different requests because the store instance becomes a global singleton. You might get state pollution.
If you're not doing SSR, it's fine to directly import the store since it will be used by only one client (in browser).
@Teebo Here is my solution: https://github.com/MikeMitterer/vue-ts-starter/tree/master/src/store
@MikeMitterer thank you so much, I will go through the repo to understand the setup, but from a glance, it looks good, thank you!
@MikeMitterer, in the file https://github.com/MikeMitterer/vue-ts-starter/blob/master/src/store/utils/index.ts
The isNotRegistered
func:
Is the check mainly for checking if the child store module is registered or it also checks the existence of the RootStore and if it has a state?
I am just wondering if the built-in hasModule
could be used.
I see that in the actions return promises in the counter store, is the a requirement fromvuex-module-decorators
or it is just a usecase example?
Been subscribed to this issue for like 2 years, the absolute state of webdev. Glad I dropped this stuff, yikes.
It is v4.0.0-rc.2 now.
But it seems to haven't no TypeScript supporting for Mutations and Actions.
Why do the Mutations or Actions have to be used by giving identifier string to trigger?
So, will there be any new feature or API to implement type suporting for mutations and actions?
@ChanningHan I've been working on full type support for vuex in my personal time, and with TS 4.1 it seems definitely possible. The only thing holding it back is a problem with TS where it obnoxiously warns about "potentially infinite blah blah". I will be updating this issue: https://github.com/vuejs/vuex/issues/1831
@ClickerMonkey Bravo~It will be exciting! ActuaIly, I used to be a heavy user of Vuex before using TS. So, I really hope to see the full type support for vuex, and thank you for your hard working on it♥
Spent several hours trying to modularize vuex store with TypeScript, I feel TS is just a way to write your code two times more. I do understand the importance of type safety, but I gave up trying to describe all types...
Spent several hours trying to modularize vuex store with TypeScript, I feel TS is just a way to write your code two times more. I do understand the importance of type safety, but I gave up trying to describe all types...
TypeScript works best when you just describe a few core domain types & the rest of your code has types inferred from how you operated on those core types & library types. It's especially important for libraries/frameworks to export APIs with types; a few any
s sneaking in from libraries creates a lots of manual typing overhead.
How should you write getters
? I'm using this example: https://next.vuex.vuejs.org/guide/typescript-support.html#simplifying-usestore-usage
Doing store.getters['foo/bar']
doesn't work because it returns 'any', how do you type hint these?
You can't. Its the same as in Vue 2. The newest version of Vuex is mainly for Vue 3 support. Wait for Vuex 5 or use vuex-module-decorators (or similar pkgs).
There's also an issue in this repo that proposes using TS 4.1 template literal types for typing
@francoism90
@3nuc I'm new to TypeScript so don't know what any of that means lol. As a workaround I'll be sticking to mapGetters as TS doesn't complain about this. State injection seems to working, but using helpers defeats the point of TS I think.
Will take a look at vuex-module-decorators
, although I'll probably wait for Vuex 5. Thanks!
https://github.com/posva/pinia - looks pretty good. Works with TypeScript out of the box.
@usernamehw Yeah, I also using Pinia as TS replacement. :)
People who prefer classical OOP-based concepts and not too functional looking code, can check out my library
I couldn't find anything on google, so is this conveniently possible? Basically the bummer for me is that I have to call
dispatch
/commit
with a given identifier string to trigger something.My vision is to define stores as Typescript classes with typed methods (getting intellisense in editor and so on) which I can call instead of
dispatch("my_action", data)
and having to look up each and everything and check for errors manually all the time.Basically my problem is that my team is building a fairly large Vue/Vuex frontend for a core product of our company, consisting of already 18 fairly complex Stores as modules, and this year stuff is going to at least quadruple in size and complexity. We already decided to go on with typescript instead of ES7 and are in the process of migrating our backend/frontend code, but this thing really feels like a bummer.
I think this is not the typical "small" use case for Vue.js, since we're building a huge enterprise frontend with loads of requirements and edge cases, but isn't vuex(/flux) supposed to scale up when complexity rises?
Has anyone experience in building complex, type safe Vuex 2.0 stores in Typescript yet? Any help here would be appreciated