Add better return types for mapState and mapGetters

I am using Single File Components in a project and aim to have the entire codebase be either Typescript or compatible with it. I’m facing a problem where using mapState causes the store properties to be discovered by Nuxt or Vetur, but they appear with a type of any and that breaks typechecks when I try to use that data for any logic other than simple rendering or mapping.

import Vue from 'vue'
import { mapState } from 'vuex'

type MyObject = {
  val1: string
  val2: number
}

type StoreState = {
  testArray: MyObject[]
}

// ...

export default Vue.extend({
  computed: {
    ...mapState(['testArray']),

    joinedTestArray(): string {
      // The type of 'testArray' is 'any'
      // 'val1' and 'val2' are also 'any'
      return this.testArray.map(({val1, val2}) => `${val1}-${val2}`)
    }
  }
})

Expected
Typescript, ESLint and Vetur checks recognise that testArray contains MyObject objects and there are no errors.

Actual
testArray is recognised as any or {} depending on which form of mapState I’ve used. None of these preserve type info about MyObject.


My question is: Am I doing something wrong and missing a type? Am I just writing it incorrectly?

I’ve found a workaround by defining a type

interface MapperWithNamespace {
  <S>(map: (keyof S)[]): { [K in keyof S]: () => S[K] }
  <S>(namespace: string, map: (keyof S)[]): { [K in keyof S]: () => S[K] }
}

that I use to cast mapState and get proper type info based on the type of store state:

...(mapState as MapperWithNamespace)<StoreState>(['testArray'])
...(mapState as MapperWithNamespace)<StoreState>('TestStore', ['testArray'])

And a final question - if I’m not mistaken and this is an actual use case would it be reasonable for this extended type be added to the interfaces for map* methods to allow better typechecks?

For my tests I’ve added
<S>(map: (keyof S)[]): { [K in keyof S]: () => S[K] }; to the Mapper<R> interface and
<S>(namespace: string, map: (keyof S)[]): { [K in keyof S]: () => S[K] }; to MapperWithNamespace<R> and that results in my code being

...mapState<StoreState>(['testArray'])
...mapState<StoreState>('TestSTore', ['testArray'])

with all correct types.