maoberlehner / vuex-map-fields

Enable two-way data binding for form fields saved in a Vuex store
MIT License
1.42k stars 85 forks source link

Question: How to use vuex-map-fields with typescript? #75

Open nowrap opened 5 years ago

nowrap commented 5 years ago

Hello, i am trying to use vuex-map-fields with typescript. The custom definition file here in the issues section i found.

But i am not getting the computed / ...mapFields expression to work in typescript. With javascript it works like a charm.

Thank for any advises! .nowrap

lhy666 commented 4 years ago

you can do like this: @Component({ computed: mapFields(['wordDetailsTemp.word']) })

yannick-milanetto commented 4 years ago

In addition to what @lhy666 said, if you need to access mapped fields within your script part (in section), you will have to tell Typescript how to infer the types. The solution I've found is to extend Vue class with your fields definition.

Example in your Vue component :

class VueWithMapFields extends Vue {
    public fieldOne!: boolean;
    public fieldTwo!: string[];
}

@Component({
    computed: mapFields(['fieldOne', 'fieldTwo']),
})
export default class MyComponent extends VueWithMapFields {
    // now I can access this.fieldOne or this.fieldTwo in lifecycle hooks, computed properties or methods
    // and I will have Typescript doing properly its typechecking job :)
}
geoidesic commented 4 years ago

@nowrap have the comments here solved your problem?

ziaadini commented 3 years ago

if you don't want build a class for each map you can do some thing like this :

...(mapFields({
      loginUsername: 'login.username',
      loginPassword: 'login.password',
      registerUsername: 'register.username',
      registerPassword: 'register.password',
      registerEmail: 'register.email',
    }) as { [key: string]: { get(): void; set(value: any): void } })

or even better define an interface

interface VuexMapFields {
  [key: string]: { get(): void; set(value: any): void }
}
...(mapFields({
      loginUsername: 'login.username',
      loginPassword: 'login.password',
      registerUsername: 'register.username',
      registerPassword: 'register.password',
      registerEmail: 'register.email',
    }) as VuexMapFields
azarashill commented 3 years ago

like?

declare module 'vuex-map-fields' {
  export function mapFields<V extends { [P in U]: any }, U extends keyof V>(
    fields: V
  ): { [P in U]: () => any }
}
tohagan commented 3 years ago

And can you use this with vuex-module-decorators Vuex classes?

lynx-r commented 3 years ago

As said @azarashill I created a file vuex-map-fields.d.ts with the type definition. Notice declare module must be single in a typings file.

declare module 'vuex-map-fields' {
  export function mapFields<V extends { [P in U]: any }, U extends keyof V>(
    fields: V
  ): { [P in U]: () => any }
}
LorensDomins commented 2 years ago

In order to use mapFields like mapGetters from vuex with namespaces, I've written according definitions; vuex-map-fields.d.ts

declare module 'vuex-map-fields' {
  interface Mapper<R> {
    <Key extends string>(map: Key[]): { [K in Key]: R }
    <Map extends Record<string, string>>(map: Map): { [K in keyof Map]: R }
  }

  interface MapperWithNamespace<R> {
    <Key extends string>(namespace: string, map: Key[]): { [K in Key]: R }
    <Map extends Record<string, string>>(namespace: string, map: Map): { [K in keyof Map]: R }
  }

  type Computed = () => any

  export const mapFields: Mapper<Computed>
    & MapperWithNamespace<Computed>
}

If you have highlighted eslint errors just add /* eslint-disable */ rule at the beginning of the file.