vuex icon indicating copy to clipboard operation
vuex copied to clipboard

Plans for complete TypeScript support with TS 4.1.0

Open ClickerMonkey opened this issue 5 years ago • 16 comments
trafficstars

What problem does this feature solve?

With the introduction of inference from template strings in TS 4.1.0 it will finally be possible to make Vuex completely type safe (validating all types, paths for commit/dispatch/modules/getters, etc).

Are there existing plans to add complete type support with the release of Vuex 4?

For reference, I've created the following project:

https://github.com/ClickerMonkey/vuex-typescript-interface

The only adjustment to the existing type system is that it would require an interface for each module and the root state - so that the modules and root state are aware of each others types. It could be optional like it currently is.

Here's how the new TS feature would solve the remaining challenge with complete type support with Vuex:

type GetEmbeddedType<O, Path extends string> = 
    Path extends `${infer A}/${infer B}` 
    ? A extends keyof O
        ? B extends keyof O[A]
            ? O[A][B]
            : never
        : never
    : never;


interface State {
    prop: {
        innerProp: number;
    }
};

type InnerPropType = GetEmbeddedType<State, 'prop/innerProp'>; // number!!

What does the proposed API look like?

Similar to what exists now, just full type support to validate types, the existence of all mutations and dispatches, and communications between the root store and it' modules.

ClickerMonkey avatar Sep 18 '20 17:09 ClickerMonkey

Yes! We're aware of TS 4.1 and this might work. To be honest I was thinking to focus TS on Vuex 5 but this kinda did change things 😅

Let's come back to this issue once TS 4.1 is released, and see how it goes. PR is welcome too! I think there's no harm trying out this feature 👍

Also, I think this can be added to both Vuex 3 & 4...?

kiaking avatar Nov 05 '20 07:11 kiaking

This would realllyyy help! Instead have to use type any just to get it to compile when it comes to your store.ts file

savannahp avatar Jan 25 '21 21:01 savannahp

I have written types to support 95% of the Vuex functionality. Because of some of the API surface I went with a wrapper approach, but the API surface is virtually identical. It supports all the mapper functions, and allows fully typed, checked access including namespaces. Would love some feedback if anyone finds it useful.

https://github.com/timritzer/typed-vuex

It requires TS 4.1 so that the template literal functionality is there, and works best with strict on.

timritzer avatar Mar 12 '21 16:03 timritzer

Any updates for better Typescript support for Vuex 4?

mohammedzamakhan avatar Apr 15 '21 18:04 mohammedzamakhan

Does anyone know how to augment the vuex types to achieve what is shown here:

type VuexOptions<M, N> = {
   namespace?: N,
   mutations: M,
}
 
type Action<M, N> = N extends string ? `${N}/${keyof M & string}` : keyof M
 
type Store<M, N> = {
   dispatch(action: Action<M, N>): void
}
 
declare function Vuex<M, N>(options: VuexOptions<M, N>): Store<M, N>
 
const store = Vuex({
   namespace: "cart" as const,
   mutations: {
      add() { },
      remove() { }
   }
})
 
store.dispatch("cart/add")
store.dispatch("cart/remove")

image

(playground)

Edit: See also the 2nd article Realize Vuex unlimited level type inference (TS 4.1 new feature), which shows support for nested modules.

glen-84 avatar May 13 '21 16:05 glen-84

Isn't is possible to get something like

store.cart.add.dispatch()
// or
store.cart.mutations.add.dispatch()
// or
store.cart.mutations.add()

This would be a whole new feature request, but would increase the DX by far IMO

Shinigami92 avatar May 13 '21 16:05 Shinigami92

@Shinigami92 There's direct-vuex, but it seems a bit awkward. This should be part of vuex itself IMO.

glen-84 avatar May 13 '21 16:05 glen-84

@glen-84 Need to test this out next week. Thanks for pointing to this, didn't know it.

Shinigami92 avatar May 13 '21 16:05 Shinigami92

Does anyone know how to augment the vuex types to achieve what is shown here:

type VuexOptions<M, N> = {
   namespace?: N,
   mutations: M,
}
 
type Action<M, N> = N extends string ? `${N}/${keyof M & string}` : keyof M
 
type Store<M, N> = {
   dispatch(action: Action<M, N>): void
}
 
declare function Vuex<M, N>(options: VuexOptions<M, N>): Store<M, N>
 
const store = Vuex({
   namespace: "cart" as const,
   mutations: {
      add() { },
      remove() { }
   }
})
 
store.dispatch("cart/add")
store.dispatch("cart/remove")

image

(playground)

Edit: See also the 2nd article Realize Vuex unlimited level type inference (TS 4.1 new feature), which shows support for nested modules.

Ya, absolutely. We use it this way. I'll try to distill it down for you. I use the above package to accomplish it.

We use modules, so I can't give you examples without modules, but the approach would be similar.

I'll make a small Gist.

timritzer avatar May 13 '21 18:05 timritzer

@glen-84 Here is a sample of how I am doing it: https://github.com/timritzer/typed-vuex-examples Feel free to ask any questions. It is working great for us, as we are any-free and have full types and auto-complete

timritzer avatar May 13 '21 21:05 timritzer

@timritzer,

Thanks for putting that together. However, I was looking for something that would not require a separate package. I was hoping to be able to augment the existing types to make them enforce the use of specific strings (as derived from the actions, mutations, etc. in each module/sub-module).

glen-84 avatar May 16 '21 14:05 glen-84

@glen-84 I mean the only package is a set of types I developed to make everything strongly typed. It's a pretty tiny package, handful of TS files, and no real functionality at run time. It has a few passthrough methods to use inferring the types, but that is it.

Feel free to copy the files and use it not as a package, I don't mind a bit. I just made it a package to follow the pattern everyone uses and make it easy to add and update.

timritzer avatar May 17 '21 03:05 timritzer

I've made my own type system that aims to be as non-intrusive as it's possible: https://github.com/kadet1090/vuex-typings for now it's not available as any JS package - I'm looking forward to do so, but I don't want for anyone to depend on something that in the end would not work out.

It supports namespaced and global modules, nested modules and has a lot of helpers - everything should be clearly described in the readme.

kadet1090 avatar May 30 '21 18:05 kadet1090

@kadet1090 looks cool! please follow this project to finish, can't wait to use it in my projects

Grawl avatar Aug 30 '21 08:08 Grawl

I had wait typing gonna be improved for about one year, there are few related PRs have no chance to be merged.

I'm considering alternatives like pinia or harlem.

miaulightouch avatar Sep 06 '21 07:09 miaulightouch

I think that there are two issues for creating better typings for vuex:

  • It's virtually impossible to create good types that are backwards compatible with current ones. And that means that they should be optional either opt-in or opt-out.
  • Someone would have to maintain them, and types for vuex are not simple - and cannot be simple because of how vuex works.

I potentially could finish my proposal of types and try to get it merged into core but this seems unlikely, as I'd need some feedback from the maintainers.

kadet1090 avatar Sep 07 '21 19:09 kadet1090