vuex-typescript-interface icon indicating copy to clipboard operation
vuex-typescript-interface copied to clipboard

How create mapping from main Store and Modules at once?

Open Suruat opened this issue 5 years ago • 9 comments

First of all, thank you for this great plugin!

When I try to use mappings it only autocomplete either module or a store (depending on what type I've provided to createHelper function). Is it possible to enable data from all modules and main store in one mapping function?

Thank you in advance!

Suruat avatar Apr 28 '19 23:04 Suruat

You can import { mapState } from 'vuex-typescript-interface' (or other mapping functions) to get the mapping functions you need for store + modules (the default Vuex stuff). The Vuex syntax uses special strings to be able to reference modules and therefore cannot be type safe at this time.

If there were a small function custom to this library that somehow allowed mapping from the store and sub modules, do you think that would be worth the few extra bytes in your build?

ClickerMonkey avatar Apr 29 '19 00:04 ClickerMonkey

@ClickerMonkey , thanks for a quick respond.

If there were a small function custom to this library that somehow allowed mapping from the store and sub modules, do you think that would be worth the few extra bytes in your build?

Yeah, I think few bytes is nothing comparing with more strait and user-friendly API of the package.

Suruat avatar Apr 29 '19 16:04 Suruat

Is there any progress on namespaced module support? I'd like very much to use this package as it seems to be the most lightweight way of adding type safety to vuex, without drastically modifying the code, and the easiest to migrate to Vuex 4 once that is released but we rely pretty heavily on ns modules.

jaredmcateer avatar Aug 14 '19 18:08 jaredmcateer

I'm working on it now, hopefully I have an acceptable solution soon. My solution doesn't modify vuex at all, but tricks your TypeScript code into having types associated to namespace paths.

You'll have to do something like this:

// use to be: 'named/module' or 'named/module/variable'

// returns string under hood but carries all type information
path<IRootStore>().module('named').module('module');
path<IRootStore>().module('named').module('module').state('variable');

ClickerMonkey avatar Aug 15 '19 03:08 ClickerMonkey

The only thing I won't be able to provide is support for something like this:

methods: {
  ...mapActions([
    'rootAction',
    'namedModule/namedAction'
  ])
}
// this.rootAction(payload)
// this['namedModule/namedAction'](payload)

That's because the result of that mapping makes rootAction and namedModule/namedAction methods on the Vue component - and Typescript doesn't have support for string concatenation of types. You would have to do:

const storePath = path<IRootStore>();
// ...
methods: {
  ...mapActions(storePath, ['rootAction']),
  ...mapActions(storePath.module('namedModule'), ['namedAction'])
}
// this.rootAction(payload)
// this.namedAction(payload)

ClickerMonkey avatar Aug 15 '19 19:08 ClickerMonkey

I see you merged this back into master in August but have not published to npm yet, is there anything I can do to help this along?

Edit:

I've done some testing off the master branch and I've run into an issue. Using something like:

  export interface PanelStore {
    namespaced: true;

    hidden: Record<string, boolean>;
    readonly hiddenByKey: (panelKey: string) => boolean;
    setHidden(payload: {panelKey: string; isHidden: boolean}): Promise<void>;
    SET_HIDDEN(payload: {panelKey: string; isHidden: boolean}): void;
  }

  export interface RootStore {
    modules: {
      panels: PanelStore
    }
  }
const key = "mainPanel";
const hiddenByKey = path<RootStore>().module('panels').getter('hiddenByKey').get();
store.getters[hiddenByKey](key);

I get the error: [tsserver 2538] [E] Type 'GetterPath<PanelStore, RootStore, "hiddenByKey", (panelKey: string) => boolean>' cannot be used as an index type.

I don't know if there is anything that could be done about that.

jaredmcateer avatar Sep 23 '19 14:09 jaredmcateer

I had to do some magic to get it to sort of work. I stopped working on it because the version of TypeScript I was working on it with just couldn't handle what needed to be done, no matter what crazy solution I came up with. The current Magic has types like GetterPath - but really that value is actually a string. I had to carry type information somehow, and this was the only thing I could do at the moment.

You might be able to just do hiddenByKey as string as ugly as that is, hopefully you don't have to do hiddenByKey as unknown as string.

Sorry this has ben so delayed, TypeScript can be pretty powerful, but it definitely has it's limits. An expert on types might be able to solve the problem, but I'm pretty spent on it.

ClickerMonkey avatar Sep 24 '19 02:09 ClickerMonkey

Too bad to hear, I appreciate the effort you put in, it's well above my current level of competence for TS. I think I'll just suffer without proper type safety until the next version.

jaredmcateer avatar Sep 24 '19 03:09 jaredmcateer

With TS 4.1.0 I should be able to get complete support for namespaced modules without using the path functions I created. We should be able to use plain strings - that TS will validate to an actual commit/dispatch/etc.

ClickerMonkey avatar Sep 18 '20 17:09 ClickerMonkey