Git Product home page Git Product logo

vuex-class-component's Introduction

Vuex Class Component

A Type Safe Solution for Vuex Modules using ES6 Classes and ES7 Decorators that works out of the box for TypeScript and JavaScript.

Installation

$ npm install --save vuex-class-component

New API

The goal of the new API is to reduce the decorator overhead and #27

How we normally define Vuex Stores.

// user.vuex.ts
const user = {
  namespace: true,
  state: {
    firstname: "Michael",
    lastname: "Olofinjana",
    specialty: "JavaScript",
  },
  mutations: {
    clearName(state ) {
      state.firstname = ""; 
      state.lastname = "";
    } 
  },
  actions: {
    doSomethingAsync(context) { ... }
    doAnotherAsyncStuff(context, payload) { ... }
  },
  getters: {
    fullname: (state) => state.firstname + " " + state.lastname,
    bio: (state) => `Name: ${state.fullname} Specialty: ${state.specialty}`,
  }
}
import { createModule, mutation, action, extractVuexModule } from "vuex-class-component";

const VuexModule = createModule({
  namespaced: "user",
  strict: false,
  target: "nuxt",
})

export class UserStore extends VuexModule {

  private firstname = "Michael";
  private lastname = "Olofinjana";
  specialty = "JavaScript";
  
  @mutation clearName() {
    this.firstname = "";
    this.lastname = "";
  }

  @action async doSomethingAsync() { return 20 }

  @action async doAnotherAsyncStuff(payload) { 
    const number = await this.doSomethingAsyc();
    this.changeName({ firstname: "John", lastname: "Doe" });
    return payload + this.fullName;
  }

  // Explicitly define a vuex getter using class getters.
  get fullname() {
    return this.firstname + " " + this.lastname;
  } 

  // Define a mutation for the vuex getter.
  // NOTE this only works for getters.
  set fullname( name :string ) {
    const names = name.split( " " );
    this.firstname = names[ 0 ];
    this.lastname = names[ 1 ];
  }
  
  get bio() {
    return `Name: ${this.fullname} Specialty: ${this.specialty}`;
  }
}

// store.vuex.ts
export const store = new Vuex.Store({
  modules: {
    ...extractVuexModule( UserStore )
  }
})

// Creating proxies.
const vxm = {
  user: createProxy( store, UserStore ),
}

On the surface, it looks like not much has changed. But some rethinking has gone into how the libary works to make for a much better developer experience.

More Powerful Proxies

With the strict option set to false we can enable greater functionality for our proxies with automatic getters and setters for our state.
For Example:

vxm.user.firstname // Michael
vxm.user.firstname = "John";
vxm.user.firstname // John

vxm.user.fullname // John Olofinjana
vxm.user.fullname = "Mad Max";
vxm.user.fullname // Mad Max
vxm.user.firstname // Mad
vxm.user.lastname // Max

Notice that we didn't have to define a mutation to change the firstname we just set the state and it updates reactively. This means no more boilerplate mutations for our state, we just mutate them directly.

This also opens up new possibilities in how we consume stores in Vue components. Example

<!-- App.vue -->
<template>
  <div class>
    <input type="text" v-model="user.firstname" />
    <div>Firstname: {{ user.firstname }}</div>

    <button @click="user.clearName()">Clear Name</button>
    <div>Bio: {{ user.bio }}</div>
  </div>
</template>

<script>
  import { vxm } from "./store";

  export default {
    data() {
      return {
        user: vxm.user,
      }
    }
  }
</script>

Notice how much boilerplate has been reduced both in defining our vuex stores and also in using them in our components. Also notice we no longer need functions like mapState or mapGetters.

Implementing More Vuex Functionality

Vuex today has additional functionalities like $watch $subscribe and $subScribeAction respectfully.

This also possible with vuex-class-component

// Watch getters in Vue components
vxm.user.$watch( "fullname", newVal => { 
  console.log( `Fullname has changed: ${newVal}` )
});

// Subscribe to mutations in Vue components 
vxm.user.$subscribe( "clearName", payload => {
  console.log( `clearName was called. payload: ${payload}` )
});

// Subscribe to an action in Vue components
vxm.user.$subscribeAction( "doSomethingAsync", {
  before: (payload :any) => console.log( payload ),
  after: (payload :any) => console.log( payload ),
})

We can even do better with Local watchers and subscribers.

const VuexModule = createModule({
  strict: false,
  target: "nuxt",
  enableLocalWatchers: true,
})

export class UserStore extends VuexModule.With({ namespaced: "user" }) {
  
  firstname = "John";
  lastname = "Doe";
  @mutation changeName( name :string ) { ... }
  @action fetchDetails() { ... }
  get fullname() {
    return this.firstname + " " + this.lastname;
  }

  $watch = {
    fullname( newValue ) { console.log( `Fullname has changed ${newValue}` },
  }

  $subscribe = {
    changeName( payload ) {
      console.log( `changeName was called with payload: ${payload}`)
    }
  }

  $subscribeAction = {
    fetchDetails( payload ) {
      console.log( `fetchDetails action was called with payload: ${payload}` )
    }
  }

}

SubModules Support

To use submodules

  const VuexModule = createModule({
    strict: false
  })

  class CarStore extends VuexModule.With({ namespaced: "car" }) {
    @getter noOfWheels = 4;

    @action drive() {
      console.log("driving on", this.noOfWheels, "wheels" )
    }
  }

We could use this sub module in a class

  class VehicleStore extends VuexModule.With({ namespaced: "vehicle" }) {
    car = createSubModule( CarStore );
  }

Now you can easily use in your Vue Components like:

  vxm.vehicle.car.drive() // driving on 4 wheels

JavaScript Support

From version 1.5.0 JavaScript is now supported fully. To use vuex-class-component in your JavaScript files, ensure your babel.config.js file has the following plugins:

module.exports = {
  ...
  plugins: [
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ["@babel/plugin-proposal-class-properties", { "loose" : true }]
  ]
}

And then use as follows

import { Module, VuexModule, getter, action } from "vuex-class-component/js";

NuxtJS Support

From verison 1.6.0 Nuxt is also supported. To use vuex-class-component with Nuxt, You add a target property to the @Module decorator and set it to "nuxt".

export class UserStore extends createModule({ target: "nuxt" }) {
  ...
}

See Old API

Old API >

vuex-class-component's People

Contributors

asmadsen avatar hectorj avatar luxaritas avatar michaelolof avatar sandronimus avatar tiagoroldao avatar toshoajibade avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vuex-class-component's Issues

Unable to access Vuex actions within Nuxt fetch hook

I'm trying to access Vuex actions from within the Nuxt fetch hook in my page components. Here's an example of a module I'm trying to access:

...
declare var $nuxt: any

@Module({namespacedPath: 'casts'})
export class CastStore extends VuexModule {
  cast?: Cast = undefined
  casts: Cast[] = []

  @mutation SET_CAST(cast: Cast) {
    this.cast = cast
  }

  @mutation SET_CASTS(casts) {
    this.casts = casts
  }

  @mutation ADD_CAST(cast) {
    this.casts.push(cast)
  }

  @action
  async fetchCasts() {
    console.log('fetching casts...')
    await $nuxt.$axios.$get('casts').then(res => {
      this.SET_CASTS(res)
    })
  }

  @action
  async fetchCast() {
    console.log('fetching cast...')
    await $nuxt.$axios.$get('casts').then(res => {
      this.SET_CAST(res)
    })
  }

}

Here's the fetch call:

async fetch ({ store }) {
  await store.dispatch('casts/fetchCasts');
}

This results in the following error:
unknown action type: casts/fetchCasts

Just thought I'd ask to see if I'm missing anything obvious.

Thanks

Accessing store instance and other properties in getters

Hi,

I've been looking for a library like this for a while, it makes so much more sense to me! I've gone through the documentation (and tests) and I believe I should be able to access the store in getters and additional access other getters.

Apologies if I've missed a step, but I can recreate this issue with namespaced modules below.

@Module({ namespacedPath: 'test/' })
class TestStore extends VuexModule {
  public num = 100;

  public get biggerNum() {
    return this.num * 100;
  }

  public get biggestNum() {
    console.log(this.biggerNum /* Undefined */, this.$store /* undefined */);
    return this.biggerNum * this.$store.state.globalNum * 100;
  }
}

export const store = new Vuex.Store({
  modules: {
    test: TestStore.ExtractVuexModule(TestStore),
  },
  state: {
    globalNum: 10
  },
  mutations: {},
  actions: {},
});

// This can be imported in vue components and used for type safety
export const vxm = {
  test: TestStore.CreateProxy(store, TestStore),
};

console.log(vxm.test.biggestNum);

Thanks!

watch, $subscribe and $subscribeAction all return void instead of the unsubscribe function

A major issue in the ProxyWatchers, to unsubscribe or unwatch, you have to call the returned function from the initial call, as described in the documentation:

https://vuex.vuejs.org/api/#watch

But the proxy returns nothing, which means you can't unsubscribe currently.

export interface ProxyWatchers {
    $watch(getterField: string, callback: ((newVal: string, oldVal: string) => void) | object, options?: {
        deep: boolean;
        immediate: boolean;
    }): () => void;
    $subscribe(mutationfield: string, callback: (payload: any) => void): () => void;
    $subscribeAction(actionField: string, callbackOrObj: SubScribeActionCallback | SubScribeActionObject): () => void;
}

module inheritance

Is it possible to use inheritance to extend module classes defined this way?

My use case is the following-

  • define a 'service' module, which is generic over a type T and exposes CRUD methods
  • extend that to concrete classes for the different types of objects in my apps

the derived classes will each need to override some methods defined in the base class, as well as add a few extra methods unique to each 'service'.

I've been trying to do this with https://championswimmer.in/vuex-module-decorators/
but it doesn't work. Or possibly it does, but only at runtime, so the compiler complains.

nuxt example or more document

Hello, this library verynice.
(Please excuse my poor English)

I cannot understand how to use on nuxt with this manual

Please give me more document or nuxt usage example.


The point I can not understand is

  • What should i write for store/index.ts
  • Is this library support only module?(Can we use only store/index.ts?)
  • Is it ok export XxxxStore only? (or must export XxxStore.ExtractVuexModule(...) also)
  • Is it requireใ€Œextends VuexModuleใ€? Document wrote > export class UserStore {
  • Is it necessary to set something else such as an nuxt.config.js

[Feature] Deep/nested mutations

Do you think it would be possible to add support for deep mutations to support state with nested fields? I'm sure it won't be an easy task, but it would sure be awesome! Nested fields are supported in that they are reactive, but obvously there's no mutation associated with them.

Work with nuxt

I would love to see this work with Nuxt as a vuex module mode. I have tried to create a module that exports the VuexModule class with ExtractVuexModule, however, it fails. Any suggestions would be great!

Class constructor xxxxx cannot be invoked without 'new'

Having become frustrated with vuex-typescript I thought I would give your library a whirl because it seems to give me more of what I am looking for. However, the information in the README is a little lightweight so I am having difficulties implementing a test module to try it out.

I based my test on the example in the README which immediately gave me a lot of errors and warnings because of my linting rules etc - mainly around the lack of type definitions on method and parameter signatures and the missing private and public declarations.

This example finally built OK for me:

import { VuexModule, mutation, action, getter, Module } from 'vuex-class-component';

interface Name {
    firstname: string;
    lastname: string;
}

@Module({ namespacedPath: 'ClassTestStore/' })
export class ClassTestStore extends VuexModule {

    private firstname: string = 'Michael';
    private lastname: string = 'Olofinjana';
    @getter public specialty: string = 'JavaScript';
    @getter public occupation: string = 'Developer';

    @mutation
    public changeName({ firstname, lastname }: Name): void {
        this.firstname = firstname;
        this.lastname = lastname;
    }

    @action()
    public async doSomethingAsync(): Promise<void> {
        setTimeout(() => {
            console.log('foo'); // tslint:disable-line
        }, 1000);
    }

    @action()
    public async doAnotherAsyncStuff(payload: any): Promise<void> {
        setTimeout(() => {
            console.log(payload); // tslint:disable-line
        }, 1000);
    }

    public get fullName(): string {
        return this.firstname + ' ' + this.lastname;
    }
}

which may or may not follow the pattern you intended.

Next I added the module to vuex as instructed and created a vxm:

import Vuex from 'vuex';
import { IState } from '../types';
import { ClassTestStore } from './modules/class_module';

export const classTestStore = ClassTestStore.ExtractVuexModule(ClassTestStore );

export const store = new Vuex.Store<IState>({
    modules: {
        classTestStore
    }
});

export const vxm = {
    classTestStore: ClassTestStore.CreateProxy(store, ClassTestStore)
};

To test I wanted to try both vxm and the module directly in a component. Your example looks like this:

@Component
export class MyComponent extends Vue {
    
    user = UserStore.CreateProxy( this.$store, UserStore );

    mounted() {
      /** Now we can easily call */
      this.user.fullName; /** Michael Olofinjana */
      this.user.occupation; /** Developer */
      this.user.changeName({ firstname:"John", lastname:"Doe" });
    }
  }

Question: What is the @Component decorator here for?

My component is defined like this:

import { vxm } from '../store';
import { ClassTestStore } from '../store/modules/class_module.ts';

export default Vue.extend({
    data() {
        return {
            classTestStore1: vxm.classTestStore,
            classTestStore2: ClassTestStore.CreateProxy( this.$store, ClassTestStore )
        };
    },
    mounted() {
        this.classTestStore1.fullName; /** Michael Olofinjana */
        this.classTestStore1.occupation; /** Developer */
        this.classTestStore1.changeName({ firstname:"John", lastname:"Doe" });

        this.classTestStore2.fullName; /** Michael Olofinjana */
        this.classTestStore2.occupation; /** Developer */
        this.classTestStore2.changeName({ firstname:"John", lastname:"Doe" });
    }
});

Problem 1
This line will not transpile:
classTestStore2: ClassTestStore.CreateProxy( this.$store, ClassTestStore )
as typescript cannot find CreateProxy as a method on ClassTestStore even though it works when creating vxm.
Putting that aside (by commenting it out) I then get

Problem 2
There is no intellisense on this.classTestStore1. It does not know about .fullname or .occupation or .changeName - but it does not fail to build either.

Problem 3
At runtime I get:

 TypeError: Class constructor ClassTestStore cannot be invoked without 'new'
    at getter (/Users/turnerk/Documents/GitHub/private/squareadmin/node_modules/vuex-class-component/dist/getters.js:6:22)
    at module.exports.__decorate (src/app/store/modules/class_module.ts:4:0)
    at Object.module.exports.__webpack_exports__.a (src/app/store/modules/class_module.ts:46:0)
    at __webpack_require__ (webpack:/webpack/bootstrap 695d4698d653203c9bcf:25:0)
    at Object.module.exports.Object.defineProperty.value (src/app/store/index.ts:1:0)
    at __webpack_require__ (webpack:/webpack/bootstrap 695d4698d653203c9bcf:25:0)
    at webpackContext (server-bundle.js:4466:9)
    at getModule (.nuxt/store.js:57:0)
    at Object.module.exports.map../index.ts (.nuxt/store.js:22:0)
    at __webpack_require__ (webpack:/webpack/bootstrap 695d4698d653203c9bcf:25:0)
    at Object.<anonymous> (.nuxt/index.js:1:0)
    at __webpack_require__ (webpack:/webpack/bootstrap 695d4698d653203c9bcf:25:0)
    at Object.<anonymous> (.nuxt/server.js:1:0)
    at __webpack_require__ (webpack:/webpack/bootstrap 695d4698d653203c9bcf:25:0)
    at server-bundle.js:92:18
    at Object.<anonymous> (server-bundle.js:95:10) statusCode: 500, name: 'TypeError' }

The last problem is the most fundamental so I need to get that sorted first.

Can you assist with any of this because I really would like to get it working. Obviously I may have made some incorrect assumptions when interpreting the example.

ReferenceError: ..._node_modules_babel_runtime_corejs2_core_js_promise__WEBPACK_IMPORTED_MODULE_0___default is not defined

Thanks to your feedback and the recent @getter bug fix I am able to compile my code. However I am now running into a runtime error that I was easily able to reproduce in my test repo.

https://github.com/SaphuA/vuex-class-component-test/blob/6f545a82c3cb1b8132505bee27d5d324b08c2386/test/src/App.vue#L27

The error is thrown as soon as I try to call an (empty) action method in my store.

https://github.com/SaphuA/vuex-class-component-test/blob/6f545a82c3cb1b8132505bee27d5d324b08c2386/test/src/store/athena/index.ts#L13

I'm currently researching if the issue is caused by webpack in combination with the circular references in your lib, but it could be something completely different...

Can't access this or module getters with Nuxt build

I'm using version 2.0.4 and having a problem with post-build Nuxt projects, even if NODE_ENV=development. I'm getting:

ERROR  Cannot read property 'firstname' of undefined
  at a.classState (2bcd2f8370f6c4fde98e.js:1:0)
  at a.classState (node_modules/vue/dist/vue.runtime.common.prod.js:6:29698)
  at a.<anonymous> (2bcd2f8370f6c4fde98e.js:1:0)
  at a.t._render (node_modules/vue/dist/vue.runtime.common.prod.js:6:35273)
  at node_modules/vue-server-renderer/build.prod.js:1:70663
  at Yi (node_modules/vue-server-renderer/build.prod.js:1:67227)
  at io (node_modules/vue-server-renderer/build.prod.js:1:70639)
  at ro (node_modules/vue-server-renderer/build.prod.js:1:70270)
  at eo (node_modules/vue-server-renderer/build.prod.js:1:67517)
  at node_modules/vue-server-renderer/build.prod.js:1:70737

To replicate, see my previous repro, which I've simply updated to the latest version - and run yarn build && yarn start.

See #41.

State undefined with new API in Nuxt

Implementing the new API, I am running into some strange problems with a virgin Nuxt install.

Accessing $store.state works fine. But getters don't seem to be able to access other class properties. So, for example: $store.getters['userStore/fullname'] returns "undefined undefined".

index.ts:

import { UserStore } from './user'
import { extractVuexModule } from 'vuex-class-component'

export const state = () => ({
  counter: 0,
})

export const modules = {
  ...extractVuexModule(UserStore),
}

user.ts has the content of the example in the README, with typos fixed.

getter use other getter is not work

interface Question {
  id: string
}
interface Answer {
  question: Question
}

@Module({ namespacedPath: 'app/', target: 'nuxt' })
export class App extends VuexModule {
  @getter questions: Questions[] = []
  @getter answers: Answer[] = []

  // this is working.
  get answeredQuestions () : Question[] {
      return this.answers.map(answer => answer.question)
  }

  // this is not working
  // Cannot read property 'some' of undefined
  get unansweredQuestions () : Questions[] {
    const answeredQuestions = this.answeredQuestions  // โ† this is undefined. why?

    return this.questions.filter((question) => {
      const isIncluded = answeredQuestions.some((answeredQuestion) => {
        return answeredQuestion.id === question.id
      })
      return !isIncluded
    })
  }
}

export default App.ExtractVuexModule(App)

Getter with method arguments

Sorry if this is the wrong place for this.

When converting an existing Vuex store, I used getters that accepted arguments, and I am not able to figure out how to do this using a VuexModule instead.

Here is an example of the existing code I am converting:

export const store = new Vuex.Store({
    state: {
        users: new Map() as Map<number, Promise<User | null>>,
    },

    getters: {
        user: (state) => (userID: number): Promise<User | null> => {
            return Promise.resolve(null); // Example code
        },
    }
});

I would use this getter by calling this.$store.getter.user(42) for example.

Here is what I've tried when converting to use VuexModule instead:

@Modue()
export class UserStore extends VuexModule {
    private users: Map<number, Promise<User | null>> = new Map();

    // Causes "TypeError: this.store.user is not a function"
    // Inspecting what "this.store" contains, I can see that "this.store.user" is undefined
    @getter user(userID: number): Promise<User | null> {
        return Promise.resolve(null);
    }
    
    // Same error as above
    @getter public user(userID: number): Promise<User | null> {
        return Promise.resolve(null);
    }

    // Same error as above
    public user(userID: number): Promise<User | null> {
        return Promise.resolve(null);
    }

    // Suggestion from issue #7 
    // Throws a Typescript error when compiling: "(TS) A 'get' accessor cannot have parameters"
    get user(userID: number): Promise<User | null> {
        return Promise.resolve(null);
    }
}

The VuexModule is created by calling:

data: function() {
    return {
        store: UserStore.CreateProxy(this.$store, UserStore);
    }
}

Is this functionality possible in vuex-class-component? Let me know if I didn't make something clear enough or you need additional information to help me. Thank you!

[Bug] Internal mutator of namespaced SUB modules not working

It seems like there's an issue when a namespace is applied to submodules. Those without namespaces work, but naming collisions are quite annoying so I'd rather have namespaces. It seems that the module is correctly registered with a namespace, but the internals are probably not taking the namespaces into account.

I've updated my previous repo: https://github.com/SaphuA/vuex-class-component-ns-repro
The error is in store.ts: https://github.com/SaphuA/vuex-class-component-ns-repro/blob/master/src/store.ts#L42

Sorry to bring you only bad news all the time ;)

NPM package update

Hey,

Could you push the latest to NPM? The latest one is 1.6

I could make a PR for readme.md that includes changes in case if you want.

Reduce boilerplate in store

    private _storages: IStorage[] = [];
    get storages() {
        return this._storages
    }
    @mutation add_storage(payload: IStorage) {
        this._storages.push(payload);
    }

    private _systemStorage?: IStorage = undefined;
    get systemStorage() {
        return this._systemStorage
    }
    @mutation change_systemStorage(payload: IStorage) {
        this._systemStorage = payload;
    }

    private _userFolder: string = "";
    get userFolder() {
        return this._userFolder
    }
    @mutation change_userFolder(payload: string) {
        this._userFolder = payload;
    }

May be we can introduce a new decorator like @Managed?
There is an example:

@managed systemStorage: IStorage;

or more complex example

@managed((payload, value) => { value.push(payload) }) storages: IStorage[];

and then just get\set it

this.storages = ...
let temp = this.storages

Namespaced modules still broken

Okay so I was a little too optimistic when I said your last commit fixed the namespace issues. It seems that only the namespace is used of the last store that is touched or used and therefore only this store is working (which was the only page I was testing at the time...).

I'll look into it and update this issue accordingly.

New API Proposal

A lot of the motivation behind this new proposal is making the Class API feel and work as much as natural classes as possible.

New Class Declaration API - (No Decorators)

import { initializeStore } from "vuex-class-component";

class Person extends initializeStore({ namespaced: true }) {

  // state
  firstname = "John";
  lastname = "Doe";
  age = 20;

  // mutation
  setBio = function( this :Person, bio :Bio ) {
    this.firstname = bio.firstname;
    this.lastname = bio.lastname;
    this.age = bio.age
  }

  // action
  async doAsyncStuff() {
    ...
  }

  // getters
  get fullname() {
    return this.firstname + " " + this.lastname;
  }

  // getter mutation (only allowed for getters)
  set fullname( fullname :string ) {
    const names = fullname.split( " " );
    this.firstname = names[ 0 ];
    this.lastname = names[ 1 ];
  }

}

interface Bio {
  firstname :string;
  lastname :string;
  age :number;
}

Cleaner Extraction of Vuex Modules and Proxies

import { extractVuexModule, createVuexProxy } from "vuex-class-component";
import { Person } from "./vuex/person.vuex"


export const store = new Vuex.Store({
  modules: {
    ...extractVuexModule( Person ),
  },
});

export const vxm = {
  person: createVuexProxy( Person, store ),
}

Automatic Getters an Mutations for your States = 10x More Powerful Proxies.

class StateStore extends initializeStore({ namespaced: true }) {

  one = "One";
  two = {
    deepTwo: "deep two",
    deepThree: {
      deeperThree: "deeper three"
      anotherDeeperThree: {
         ok: "Ok",
        cool: "Cool"
      }
    }
  }

}


const stateStore = createVuexProxy( StateStore, store );

stateStore.one // "One"
stateStore.one = "Changed One";
stateStore.one // Changed One

stateStore.two.deepTwo // "deep two";
stateStore.two.deepTwo = "Changed deep two";
stateStore.two.deepTwo // Changed deep two.

stateStore.two.deepThree.anotherDeeperThree.cool // "Cool";
stateStore.two.deepThree.anotherDeeperThree.cool = "Changed Cool"; // This will only mutate the cool property not the entire object.
stateStore.two.deepThree.anotherDeeperThree.cool // "Changed Cool"

What do you think?

export CreateProxy and ExtractVuexModule as functions

Currently to create a proxy or to extract a module you need to type the class 2 times. From looking at the code I believe it would be fairly easy to export createProxy(store, moduleClass) and exportVuexModule(moduleClass) as stand alone functions and therefore reducing verbosity a little bit.

I'm open to doing a PR if this is a feature you want.

The end result would be :

 import {createProxy, extractVuexModule} from 'vuex-class-component'

  export const store = new Vuex.Store({
    modules: {
      user: extractVuexModule( UserStore ),
      pages: extractVuexModule( PagesStore ),
      story: extractVuexModule( StoryStore ),
    }
  })

  export const vxm = {
    user: createProxy( store, UserStore ),
    pages: createProxy( store, PagesStore ),
    story: createProxy( store, StoryStore ),
  }

There might even be a way to use TS generics to achieve similar results. It could also use partial application and currying to pass the store only once to the createProxy function. I also believe this could all remain completely type safe if done correctly.

mutations_cache being shared across several modules

Hello,

I'm still in the process of migrating to v2, and I am encountering a strange error.
I am declaring several modules as described in the ReadMe, and trying to add all of them to my Vuex store, like so:

export const main = new Vuex.Store({
  modules: {
    ...extractVuexModule(ModuleA),
    ...extractVuexModule(ModuleB),
    ...extractVuexModule(ModuleC),
    ...extractVuexModule(ModuleD),
  },
});

export const vxm = {
  moduleA: createProxy(main, ModuleA),
  moduleB: createProxy(main, ModuleB),
  moduleC: createProxy(main, ModuleC),
  moduleD: createProxy(main, ModuleD),
};

Those different modules have each their state and each one has at least one explicit mutation.
The problem is, when I am trying to access these explicit mutations through vxm, I am getting a "is not a function" error.

By investigating further, I saw that every module has the mutation of the last extracted module (Module D here).
By using Chrome debugger, I found that VuexClass.prototype in
Line 54 in module.ts

VuexClass.prototype.__mutations_cache__.__explicit_mutations__ = fromPrototype.mutations.explicitMutations;

is shared across my modules, and thus is overridden each time a new module is registered.
The creation of the store is executing as expected, but the creation of the proxies are using this shared prototype and so are affecting the same explicit mutations to every modules.

Accessing Nuxt Router inside Vuex module

I've been trying out this package in a Nuxt app, and I'm just trying to find a way to change paths with Vue Router inside a Vuex action. Normally that would be with this.$router.push('...'), but I can't access this.$router inside the Vuex module. Can anyone let me know if this is possible?

@getters - Cannot call a class as a function

The following is throwing the exception for me on the getter decorator

const ctr = target.constructor();

classCallCheck.js?d225:3 Uncaught TypeError: Cannot call a class as a function
    at _classCallCheck (classCallCheck.js?d225:3)
    at VuexModule.UserStore (UserStore.vuex.ts?7299:3)
    at getter (getters.js?470c:6)
   // UserStore.vuex.ts
  import { VuexModule, mutation, action, getter, Module } from 'vuex-class-component'    
      
  @Module({ namespacedPath: 'user/' })    
  export class UserStore extends VuexModule {                                 
                                                                              
    @getter public foo: string = 'bar'                                        
                                                                              
    @mutation                                                                 
    public updateProfile(profile: string) {                                                    
     this.foo = profile                                                                       
    }                                                                                          
                                                                                               
    @action()                                                                                  
    public getUserProfile(): any {                                                             
     // get profile                                                                           
    }                                                                                          
                                                                                               
  }                                                                                            
                                                                                               
  export const user = UserStore.ExtractVuexModule( UserStore )
// tsconfig.json
{                                                                                      
    "compilerOptions": {  
      "target": "esnext",                 
      "module": "esnext",                                                     
      "strict": true,                                                         
      "jsx": "preserve",                                                      
      "importHelpers": true,                                                  
      "moduleResolution": "node",                                                              
      "experimentalDecorators": true,                                                          
      "esModuleInterop": true,                                                                 
      "allowSyntheticDefaultImports": true,                                                    
      "sourceMap": true,                                                                       
      "baseUrl": ".",                                                                          
      "types": [                                                                               
        "webpack-env",                                                                         
        "mocha",                                                                               
        "chai"                                                                                 
      ],                                                                                       
      "paths": {                                                                               
        "@/*": [    
          "src/*"    
        ]    
      },    
      "lib": [    
        "esnext",    
        "dom",    
        "dom.iterable",    
        "scripthost"    
      ]    
    },    
    "include": [  
      "src/**/*.ts",    
      "src/**/*.tsx",    
      "src/**/*.vue",    
      "tests/**/*.ts",    
      "tests/**/*.tsx"    
    ],    
    "exclude": [  
      "node_modules"    
    ]    
  }    

Any ideas?

Can't access store instance from @action

Is there a way to access the store instance from within an @action method? Using vanilla Vuex, this refers to the store instance.

Specifically, I'm trying to do this to access store.$axios, which Nuxt decorates onto the store instance:

actions: {
  async fetch() {
    // `this` is Vuex Store instance
    // `this.$axios` is defined.
  }
}

I tried using @action({ mode: 'raw' }) and getRawActionContext(this), but the resulting context is the same. And skimming through the source, it looks like the $store instance from the createProxy call is never persisted.

@action({ mode: 'raw' })
async fetch() {
  const context = getRawActionContext(this);
  // context === this
  // this.$axios is not defined.
}

Do you have any suggestions? My current workaround is to pass it into the @action handler from the calling component. But, this shouldn't be necessary, as I can access this.$axios from action handlers defined in vanilla Vuex.

[BUG] npm package Version 2.3.2 still has pr #64 related issues.

I download your lastest 2.3.2 package version from npm, it still has pr #64 related issues. But when I download your source code from your master repository directly and compile to js, it is ok, no those issues. So, I think your npm package was compiled from old source code version. Please update your npm package, thanks a lot! Please forgive my poor english!

Calling getter in mutation

I am trying to call a getter with a mutation, and it seems not to work:

import { createModule, createProxy, mutation, action } from 'vuex-class-component'

import { Investigation, InvestigationId, InvestigationsState } from './types'

const VuexModule = createModule({
  namespaced: 'investigations'
})

export class Investigations extends VuexModule implements InvestigationsState {
  investigations: Investigation[] = []
  currentInvestigationIndex = -1

  get current (): Investigation | undefined {
    return this.currentInvestigationIndex >= 0 ? this.investigations[this.currentInvestigationIndex] : undefined
  }

  get id () {
    return (id: InvestigationId): Investigation | undefined => this.investigations.find(i => i.id === id)
  }

  @mutation
  changeSomething ({ investigationId, thing }: { investigationId: InvestigationId, thing: string }): void {
    // ERROR: this.id is not a function
    const investigation = investigationId ? this.id(investigationId) : this.current
    // Do stuff
  }
}

I can work around this by using a proxy within the mutation:

const me = createProxy(this.$store, Investigations)
const investigation = investigationId ? me.id(investigationId) : me.current

But I thought that this could have been done at a higher level.
Am I missing something?

Creating SubModules fails with error

Hello,

I have created two modules for my store (UserStore and AppStore), and I tried making the AppStore a submodule of UserStore, as follows:

UserStore.ts:

import { VuexModule, Module }         from "vuex-class-component";
import { mutation, action, getter }       from "vuex-class-component";
import axios                                        from 'axios';
import AppStore                                 from '@/stores/AppStore';

@Module({ namespacedPath: "user/" })
export default class UserStore extends VuexModule {
// ...
private app = AppStore.CreateSubModule(AppStore);
//...
}

AppStore.ts:

import { VuexModule, Module }                       from "vuex-class-component";
import { mutation, action, getter }                 from "vuex-class-component";
import axios                                        from 'axios';
import { EventForm, Person, GApiObject, Session }   from '@/interfaces';

@Module({ namespacedPath: "app/" })
export default class AppStore extends VuexModule {
//...
}

store.ts:

import Vue          from 'vue';
import Vuex         from 'vuex';
import UserStore    from '@/stores/UserStore';
import AppStore     from '@/stores/AppStore';

Vue.use(Vuex);

// Extract Vuex Modules
const UserModule = UserStore.ExtractVuexModule(UserStore);
const AppModule  = AppStore.ExtractVuexModule(UserStore);

// export default new Vuex.Store({
//     modules: {
//         UserModule,
//     }
// });

// Create store object
export const store = new Vuex.Store({
    modules: {
        UserModule,
        AppModule
    }
});

// Create and export vuex manager object
export const vxm = {
    app:  AppStore.CreateProxy(store, AppStore)   as AppStore,
    user: UserStore.CreateProxy(store, UserStore) as UserStore,
};

main.ts:

/* Import VUE stuff */
import Vue                  from 'vue';
import App                  from './App.vue';
import router               from './router';
import { store, vxm }       from './store';

// other imports..

Vue.prototype.$vxm      = vxm;

new Vue({
    router,
    store,
    render: (h) => h(App),
    created: () => {
        console.log('created.');
    }
}).$mount('#app');

It compiles successfully, however when I enter the web page, I get the following error:

module.js:72 Uncaught TypeError: Cannot assign to read only property 'app' of object '#'
at module.js:72
at Array.map ()
at s (module.js:69)
at Function.t.CreateProxy (module.js:23)
at Module.cd49 (store.ts:29)
at r (bootstrap:78)
at Object.0 (bootstrap:151)
at r (bootstrap:78)
at a (bootstrap:45)
at bootstrap:151

Did I do something wrong, or is there an issue with the package?

[BUG]Mutation in Action doesn't work sometimes.

If I try to call Mutation through setter in Action with the following code, I may get the error.

const VuexModule = createModule({
  namespaced: "auth",
  strict: false,
});

export default class Auth extends VuexModule {
  private _user: User | null = null;

  get user() {
    return this._user;
  }

  set user(v: User | null) {
    this._user = v;
  }

  @action
  async isSignedIn() {
    let user = this.user;
    if (!user) {
      user = await getUser();
      this.user = user; // `$store.commit is not a function` error
    }
    return user ? true : false;
  }
}

There is a procedure that always occurs in my app, but the conditions are unknown.

When the error occurs, the $store in proxy.js:379:50 looks like this

$store: {
  user: null,
  __auth_internal_getter__: function,
  __auth_internal_mutator__: function,
  __proto__: Object
}

Thanks for your help.

ProxyWatchers small declaration issue

Hello, thanks for this library, it's very useful !

I use the ProxyWatchers in my code, but since I create the proxies only once and use an interface to access them, I had to fetch the type manually with:

import { extractVuexModule, createProxy } from "vuex-class-component";
import { ProxyWatchers } from "vuex-class-component/dist/interfaces";

Hitting "/dist/interfaces" doesn't really pleases me. Could you move it to the root declaration?

Also I noticed that in SubScribeActionCallback, "before" and "after" functions are both mandatory, they should be optional (either before, after, or before + after)

Actions are not working in production (Nuxt w/ TypeScript)

I'm currently using vuex-class-component in a simple Nuxt Typescript project. Everything works fine in development, but when I run npm run build; npm run start and try to call an action, nothing happens. No functionality or errors.

I'll try to find some time to setup an example repo.

Using vuex manager inside template

I know you're not a fan of using .vue files, but that is not something I will be able to refactor away anytime soon...

I am wondering if there's a way to use the vxm directly inside my templates without the need for getters.

So instead of doing this:

<template>
  <div>
    {{foo}}
  </div>
</template>

import { vxm } from './store';

@Component
export default class extends Vue {
  get foo() { return vxm.athena.foo; }
}

I can do this instead:

<template>
  <div>
    {{vxm.athena.foo}}
  </div>
</template>

import { vxm } from './store';

@Component
export default class extends Vue {
}

Store initial value cannot be null

Hello,

I am really liking this library, there is just one thing which bothers me. I cannot initialize my state properties with null. This will break the library with the following error:

module.js?843e:125 Uncaught TypeError: Cannot read property 'type' of null
    at subModuleObjectIsFound (module.js?843e:125)
    at eval (module.js?843e:96)
    at Module.__decorate (tslib.es6.js?9ab4:54)
    at eval (msv.ts?e0ac:7)
    at Module../src/store/modules/msv.ts (app.js:9166)
    at __webpack_require__ (app.js:724)
    at fn (app.js:101)
    at eval (index.ts?0613:1)
    at Module../src/store/index.ts (app.js:9142)
    at __webpack_require__ (app.js:724)

So a property that would look like this will break the library:

@getter
public propertyName: SomeObject | null = null;

Initializing with undefined is not possible, because this will make the property lose reactivity.

I am not an expert on typescript, but would it be possible to change to subModuleObjectIsFound function to the following:

function subModuleObjectIsFound(stateValue: any): stateValue is SubModuleObject {
  if (stateValue === null) {
    return typeof stateValue === "object";
  }
  return typeof stateValue === "object" && stateValue.type === _submodule
}

Feature request: create proxy inside of VuexModule

Wow this library is fantastic -- makes working with vuex modules much more intuitive and easy to use w/ type safety and intellisense!

The first module I implemented had to call out to another module that houses same shared logic, so I implemented using the raw action context, which worked but I lost all the type safety

import { VuexModule, Module, getter, action, getRawActionContext, mutation } from 'vuex-class-component';
import RootState from '../../types/RootState'
import Product from '../../types/product/Product';
import bodybuilder from 'bodybuilder';

export interface SubscriptionState {
  subscriptions: Product[] | [],
}

@Module({ namespacedPath: 'subscriptions/' })
export class SubscriptionStore extends VuexModule {
  @getter items: Product[] = []

  @mutation
  loadItems (items: Product[]) {
    this.items = items
  }

  @action({ mode: 'raw'})
  load (): Promise<void> {
    const context = getRawActionContext(this)
    const query = bodybuilder()
      .query('match', 'category.name', 'Subscriptions')
      .build()

    return context.dispatch('product/list', { query, start: 0, size: 10, updateState: false }, { root: true }).then(resp => {
      const subscriptions = (resp.items as Product[]).sort((p1, p2) => +p1.order - (+p2.order))
      context.commit('loadItems', subscriptions)
    }).catch((err) => {
      console.error(err)
    })
  }
}

Would it be possible to create a proxy that takes a VuexModule as a constructor? So inside my subscription vuex module it would look like:

product = ProductStore.CreateProxy(ProductStore, this)

Could that proxy method leverage the raw context to generate the necessary proxy? And then you have all the type safety you need when dispatching an action to another module

watchers and subscribers in nuxt

Hi,

In nuxt.js subscribers etc. will work only if you prepend related property with static, like static $subscribe = { ... }, otherwise createLocalSubscriber in proxy.ts will return on if( subscriptionMap === undefined ) return;. Not sure if this is related to nuxt only.

Another thing is that state is not available in subscribers and actionSubscribers, though normally Vuex passes it as second parameter. Any reason its not implemented here?

Changes between 1.9.0 and 2.0.0

Hey there,

I wanted to ask what kind of changes you made between v1.9.0 and v2.0.0 and if there are breaking changes.

Thanks!

[Feature] Add field name to internal mutations

When one uses the strict=false method all the mutations look like this in the Vue dev tools:
MyStoreName/__mystorename_internal_mutator__

I think having the field name in there would help a lot with debugging with Vue Dev Tools.

Missing extends on generic type in proxy and submodule declarations

Hello,

First of all, thank you very much for your work.
I tried migrating to v2 on a project using vue-cli, and unfortunately got an error during compilation, specifically:

ERROR in node_modules/vuex-class-component/dist/proxy.d.ts
5:101 Type 'T' does not satisfy the constraint 'new (...args: any) => any'.
    3 | export declare function createProxy<T extends typeof VuexModule>($store: any, cls: T): ProxyWatchers & InstanceType<T>;
    4 | export declare function createLocalProxy<T extends typeof VuexModule>(cls: T, $store: any): InstanceType<T>;
  > 5 | export declare function _createProxy<T>(cls: T, $store: any, namespacedPath?: string): InstanceType<T>;
      |                                                                                                     ^
    6 |

and:

ERROR in node_modules/vuex-class-component/dist/proxy.d.ts
5:101 Type 'T' does not satisfy the constraint 'new (...args: any) => any'.
    3 | export declare function createProxy<T extends typeof VuexModule>($store: any, cls: T): ProxyWatchers & InstanceType<T>;
    4 | export declare function createLocalProxy<T extends typeof VuexModule>(cls: T, $store: any): InstanceType<T>;
  > 5 | export declare function _createProxy<T>(cls: T, $store: any, namespacedPath?: string): InstanceType<T>;
      |                                                                                                     ^
    6 | 

I tracked those errors to a missing extends in the declaration files of proxy and submodule classes.

Changing:

export declare function createSubModule<T>(Cls: T): InstanceType<T>;

to:

export declare function createSubModule<T extends typeof VuexModule>(Cls: T): InstanceType<T>;

and doing the same for proxy seems to fix my problem.

Some problems getting started

This library seems to be exactly what I need to move over to Vue. I'm pretty close to getting it to work the way I want, but there are some typing/module issues.

The first issue is that the CreateProxy() method is not available on my store. This is because it sees it as the interface VuexModule (instead of the class with the same name) which does not contain this method. It does seem to compile just fine so it might be a VsCode / Vetur issue. This is not a huge problem - but it is very confusing and not mentioned in the readme.

import { AthenaStore } from './store/athena';
@Component
export default class extends Vue {
  // Error -> Property 'CreateProxy' does not exist on type 'typeof AthenaStore'
  // Because of this I have to specfically define the field as `AthenaStore`
  private athena: AthenaStore = AthenaStore.CreateProxy(this.$store, AthenaStore); 

The other issue is with the Manager approach. After some searching I found a closed issue that recommended casting it to the store type to help Vetur. Perhaps this is useful information to add to the readme?

Then importing the Manager was different as well. My guess is that this is because our tsconfig has module=esnext (instead of commonjs as in your examples) which handles const exports differently. So I have to do a default import to some field first. Perhaps this could use some improvement and clarification the readme?

Then when I try to use the manager in the mounted hook it is undefined. It does seem to get a value later on in the cycle.

export const vxm = {
  athena: AthenaStore.CreateProxy(store, AthenaStore) as AthenaStore,
}

import * as store from './store'; // different import as in docs
@Component
export default class extends Vue {
  mounted() {
    store.vmx; // this is undefined??
  }
}

Also, I came across this example repo in one of the closed issues. Seems to be useful enough to link to it in the readme. https://github.com/michaelolof/vuex-class-component-simple

[Bug] Actions force you to be async

I am creating a new project with Nuxt and I have added your library (thanks for your work by the way ;) ) but there is a problem with the Action decorator.

It force me all the time to return promises even if I don't want to.

For example in this piece of code:

  @action test() {
    console.log('IP UP UASD!')
    return 1
  }

I get the following error:

Captura de pantalla 2020-04-20 a las 9 44 38

So even If I don't put the async there and I ignore the error suppressing it with // @ts-ignore, when I use it in my component I get a promise, and again I am force to put async and await inside the method of the component without sense.

I guess this is fault of the types, but I try to take a look and see If I could create a pull request to fix it but I am not that proficient with Typescript and how the decorators work.

How can I make it work with as a non async action?

Thanks in advance.

Has no exported createModule

good day. I just want to know what's the cause of this issue. I can't continue exploring the library because of this issue in my first step of working on it. Hoping you can help me
Module '"../../../node_modules/vue-class-component/lib"' has no exported member 'createModule'. Did you mean to use 'import createModule from "../../../node_modules/vue-class-component/lib"' instead?

[v2.0.4] Component breaks if no explicit mutation is defined

Hello,
thanks for the work you are doing. I am writing to signal an easily fixable bug of the component.

How to reproduce

Create a vuex class component with no mutations, in my particular case the component had the following code:

class MyComponent extends {
  private authData: any;

  get tokenData() : Auth0DecodedHash | null {
      return this.authData;
  }

  set tokenData(authData: Auth0DecodedHash | null) {
    if (authData) {
      this.authData = authData;
      localStorage.setItem("token", JSON.stringify(authData));
    } else {
      localStorage.removeItem("token");
    }
  }

  @action async login(): Promise<void> {
    try {
      const authData = await this.handleAuthentication() // PLACEHOLDER
      if (authData) {
        this.tokenData = authData;
      }
    } catch (error) {
      handleError(error); // PLACEHOLDER
    }
  }

  private async handleAuthentication(): Promise<any> {
    // perform authentication handling
  }
}

by serving your application your application should break (assuming you added correctly the module to the vuex store.

In particular, thanks to the chrome debugger I found out where is the problem:

// If prototype field is an explicit mutation
var fieldIsExplicitMutation = (typeof descriptor.value === "function" &&
  explicitMutationNames.indexOf(field) > -1); // BREAKS HERE
if (fieldIsExplicitMutation) {
  var mutation = function (state, payload) { return descriptor.value.call(state, payload); };
  explicitMutations[field] = mutation;
  return "continue";
}

Workaround

Just add a dummy mutation

class MyComponent extends {
  // ...
  @mutation dummy() : void {
    throw new Error("Should never call this method, it is a workaround");
  }
}

Actual Fix

note that if explicitMutations is an empty object explicitMutationNames is undefined, therefore, adding an additional check would make this error disappear. I would revise how the explicitMutationNames array is created anyway.

Thank you ๐Ÿ‘

Namespaced modules' path broken when code is minified

Hello,

While using version 2.0.4, module declaration is kind of broken in minified code due to the path being pulled from the class' name.
Problem is, the class name is being mangled while using vue-cli in its default configuration.

The result (for me) is that my store only has a single module (named t in my output), even if I declare several modules. This single module contains every state property of my modules but only the mutations and actions of the last declared one.

[v2.1.3] Components getters and actions break

NOTE: Everything works in version 2.1.1: I suggest a revert

from this example

import { createModule, action, mutation, getter } from "vuex-class-component";
import { VuexModuleOptions } from 'vuex-class-component/dist/interfaces';

const VuexModule = createModule({
    namespaced: "exampleStore",
    strict: false,
} as VuexModuleOptions);

export default class ExampleStore extends VuexModule {
    private incrVal : number = 0;

    get currentExampleValue() : number {
        // if "this.incrVal = this.incrVal + 1;" is commented it works
        this.incrVal = this.incrVal + 1; // error, store.commit is not a function
        return this.incrVal;
    }
}

creating a proxy of this component like this fails

<template>
    <div>
      <strong> Computed: {{computedInfo}} </strong><br/>
      <strong> value from Vuex: {{example.currentExampleValue}}</strong><br/>
    </div>
</template>
<script lang="ts">
import Vue from 'vue';

import { example } from "@/vuex";
import Component from 'vue-class-component';

@Component({})
export default class HomePage extends Vue {
    example = example;
    mounted() : void {
        console.log("mounted");
    }

    get computedInfo() : string {
        return "Computed" + " " + "example";
    }
}
</script>

Here a copy of the stack trace

TypeError: store.commit is not a function
    at Object.set (proxy.js?fe19:250)
    at Object.get (index.ts?9da9:13)
    at getter (module.js?843e:170)
    at wrappedGetter (vuex.esm.js?2f62:777)
    at Vue.eval (vuex.esm.js?2f62:95)
    at Watcher.get (vue.runtime.esm.js?2b0e:4473)
    at Watcher.evaluate (vue.runtime.esm.js?2b0e:4578)
    at Vue.computedGetter [as exampleStore/currentExampleValue] (vue.runtime.esm.js?2b0e:4830)
    at Object.get [as exampleStore/currentExampleValue] (vuex.esm.js?2f62:567)
    at Object.get (proxy.js?fe19:388)

Let's move to actions now

given the following

import { createModule, action, mutation, getter } from "vuex-class-component";
import { VuexModuleOptions } from 'vuex-class-component/dist/interfaces';

const VuexModule = createModule({
    namespaced: "exampleStore",
    strict: false,
} as VuexModuleOptions);

export default class ExampleStore extends VuexModule {
    private incrVal : number = 0;

    get currentExampleValue() : number {
        return this.incrVal;
    }
    
    @action async bicrement() : Promise<void> {
        this.incrVal+=2;
    }
}

if you use it it breaks

<template>
    <div>
      <strong> Computed: {{computedInfo}} </strong><br/>
      <strong> value from Vuex: {{example.currentExampleValue}}</strong><br/>
      <button @click="triggerIncrement()"> INCREMENT! </button><br/>
    </div>
</template>
<script lang="ts">
import Vue from 'vue';

import { example } from "@/vuex";
import Component from 'vue-class-component';

@Component({})
export default class HomePage extends Vue {
    example = example;

    mounted() : void {
        console.log("mounted");
    }

    get computedInfo() : string {
        return "Computed" + " " + "example";
    }

    triggerIncrement() : void {
        this.example.bicrement();
    }
}
</script>

Here the stack trace

TypeError: this.example.bicrement is not a function
    at VueComponent.triggerIncrement (HomePage.vue?ac04:39)
    at click (eval at ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"367216db-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/HomePage.vue?vue&type=template&id=c6bdc170&scoped=true& (app.js:1088), <anonymous>:32:24)
    at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
    at HTMLButtonElement.invoker (vue.runtime.esm.js?2b0e:2179)
    at HTMLButtonElement.original._wrapper (vue.runtime.esm.js?2b0e:6911)
logError @ vue.runtime.esm.js?2b0e:1888
globalHandleError @ vue.runtime.esm.js?2b0e:1879
handleError @ vue.runtime.esm.js?2b0e:1839
invokeWithErrorHandling @ vue.runtime.esm.js?2b0e:1862
invoker @ vue.runtime.esm.js?2b0e:2179
original._wrapper @ vue.runtime.esm.js?2b0e:6911

getter functions can't contain payload

Hy, I wonder how I can create a getter function which can contain any parameters. If I create a function and add the @getter decorator like @getter foo(id: number) {..} i throws an webpack error inside the browser. Here is the error: WEBPACK_IMPORTED_MODULE_2__store.b.testStore.foo is not a function

Implement more of the Vuex functionality

The motivation of encapsulating more of the Vuex functionality is to extend the type-safety to more parts of Vuex.

Root Vuex Module

The first step would be to encapsulate the creation of the root Vuex module, then we can also pass pre-made proxies to actions and getters.
To do this we are missing options for plugins, strict, and devtools.

Class decorator

import { VuexClass } from 'vuex-class-component'

@Store({
  strict: boolean,
  devtools: boolean,
  plugins: Plugin<Store>[]
})
class Store extends VuexClass {
}

Constructor options

import { VuexClass } from 'vuex-class-component'

class Store extends VuexClass {
  constructor() {
    super({
      strict: boolean,
      devtools: boolean,
      plugins: Plugin<Store>[]
    })
  }
}

Configuring sub-modules

import { VuexClass } from 'vuex-class-component'

class Store extends VuexClass {
  auth = new AuthModule()
}

class AuthModule extends Store.SubModule(store => store.auth) {
}

Other possibilities

We could implement decorators for Watch, Subscribe, and SubscribeAction. This way we could have actions or mutations be called as reactions to other parts of the state without the origin knowing what methods to call after a change. I.e. Fetch different kinds data after login state changed/login action is called/login mutation is called without them knowing what actions or mutations that relies on it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.