championswimmer / vuex-module-decorators

TypeScript/ES7 Decorators to create Vuex modules declaratively
https://championswimmer.in/vuex-module-decorators/
MIT License
1.8k stars 170 forks source link

How should I use the VuexModule constructor to implement an abstract store #296

Open tmarqxx opened 4 years ago

tmarqxx commented 4 years ago

Hi there.

I'm trying to set up my modules to extend an AbstractStore class that implements basic actions and mutations for simple CRUD operations. Whereas the children of AbstractStore implement their respective state, getters and any other actions/mutations that are unique to them.

To implement this I'm passing an endpoint string to its constructor, which is then used in the HTTP requests. Here's a rough example of how I'm trying to implement this:

// store.ts

import { VuexModule, Module, Mutation, Action } from 'vuex-module-decorators'
import { $axios } from '~/utils/api'

@Module({
  stateFactory: true,
  namespaced: true
})
export default abstract class AbstractStore extends VuexModule {

  endpoint: string

  // common state

  constructor(endpoint: string) {
    super() // This displays an error
    this.endpoint = endpoint
  }

  // CRUD Mutations

  @Action
  async create() {
    try {
      const data = this.getProperties
      const response = await $axios.$post(this.endpoint, data)
      this.CREATE(response.data)
    } catch (error) {
      console.error(error)
    }
  }

  @Action
  async read(id: number) {
    try {
      const response = await $axios.$get(this.endpoint + `/${id}`)
      this.READ(response.data)
    } catch (error) {
      console.error(error)
    }
  }

  @Action
  async update() {
    try {
      const data = this.getProperties
      const response = await $axios.$put(this.endpoint + `/${data.id}`, data)
      this.CREATE(response.data)
    } catch (error) {
      console.error(error)
    }
  }

  @Action 
  async delete(id: number) {
    try {
      await $axios.$delete(this.endpoint + `/${id}`)
      this.DELETE(id)
    } catch (error) {
      console.error(error)
    }
  }

  abstract get getProperties(): any
}
// users.ts

import { Module, Mutation, Action } from 'vuex-module-decorators'
import { $axios } from '~/utils/api'
import AbstractStore from './store'

const endpoint = '/api/users'

@Module({
  stateFactory: true,
  namespaced: true
})
export default class UsersStore extends AbstractStore {

  // user state

  constructor() {
    super(endpoint)
  }

  // Other Mutations and Actions

  get getProperties(): any {
    return {
      // package up the user state
    }
  }
}

My issue is that I'm not sure how to call the VuexModule constructor in the AbstractStore constructor. When simply calling super(), my editor shows an error saying:

Expected 1 arguments, but got 0. ts(2554)
vuexmodule.d.ts(16, 17): An argument for 'module' was not provided.

So what should I pass to super to make this work? Can this implementation even work as I want it to? Would love some insight, thanks!

kjesien commented 4 years ago

Hello,

I had very similar problem. Each of the Vuex store modules expect the parent module as argument.

Simply in AbstractStore define constructor like:

constructor(module: Mod<ThisType<any>, any>, endpoint: string) {
  super(module);
  this.endpoint = endpoint
}

and in UsersStore

constructor(module: Mod<ThisType<any>, any>) {
  super(module, endpoint);
}

Let us know if it work.