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

Type inference with generics

Open gregoirechauvet opened this issue 5 years ago • 1 comments

Hey, thanks for your awesome lib!

When using generics in mutations (and actions too), lookup types are not inferred as accurately as they could be.

Here is my store definition:

import { Module, MutationTree } from 'vuex-typescript-interface';

interface Filters {
  search: string;
  toggleThing: boolean;
}

interface FiltersModule {
  filters: Filters,
  UPDATE_FILTERS<T extends keyof Filters>(payload: { key: T, value: Filters[T] }): void;
}

const mutations: MutationTree<FiltersModule> = {
  UPDATE_FILTERS: (state, {key, value}) => {
    state.filters = {
      ...state.filters,
      [key]: value
    };
  }
}

const module: Module<FiltersModule, RootState> = {
  state: {
    filters: {
      search: '',
      toggleThing: false
    }
  },
  mutations: mutations
}

export default module;

And when I use the mutation in a component:

store.commit('UPDATE_FILTERS', { key: 'search', value: 'foo' }) // Working, as expected
store.commit('UPDATE_FILTERS', { key: 'search', value: 4 }) // Fail, of course
store.commit('UPDATE_FILTERS', { key: 'search', value: true }) // Does not fail even if it should 😞

It seems that the union of all possible types is inferred, so here value can be string or boolean, instead of being specific to the key used.

Screenshot from 2019-08-27 17-29-59

But TypeScript should be able to handle this situation correctly. It does work with a standard function:

interface Filters {
  search: string;
  toggleThing: boolean;
}

function test<T extends keyof Filters>(payload: { key: T, value: Filters[T] }): void {
  // Do nothing
}

test({ key: 'search', value: 'foo' }) // Ok
test({ key: 'search', value: 4 }) // Fail
test({ key: 'search', value: true }) // Fail too

Is it something that can be improved? :slightly_smiling_face:

gregoirechauvet avatar Aug 27 '19 15:08 gregoirechauvet

I'll look into it as I work on the new version for Vuex 4

ClickerMonkey avatar Sep 18 '20 17:09 ClickerMonkey