ClickerMonkey / vuex-typescript-interface

Adding magical type safety to Vuex without additional code
MIT License
44 stars 4 forks source link

How create mapping from main Store and Modules at once? #1

Open Suruat opened 5 years ago

Suruat commented 5 years ago

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!

ClickerMonkey commented 5 years ago

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?

Suruat commented 5 years ago

@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.

jaredmcateer commented 5 years ago

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.

ClickerMonkey commented 5 years ago

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 commented 5 years ago

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)
jaredmcateer commented 5 years ago

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.

ClickerMonkey commented 5 years ago

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.

jaredmcateer commented 5 years ago

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.

ClickerMonkey commented 4 years ago

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.