{"id":22489985,"url":"https://github.com/sascha245/vuex-simple","last_synced_at":"2025-07-12T07:33:15.144Z","repository":{"id":72031146,"uuid":"151462553","full_name":"sascha245/vuex-simple","owner":"sascha245","description":"A simpler way to write your Vuex store in Typescript","archived":false,"fork":false,"pushed_at":"2019-10-16T18:55:21.000Z","size":151,"stargazers_count":179,"open_issues_count":3,"forks_count":15,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-06-21T01:05:48.410Z","etag":null,"topics":["typescript","vue","vuejs","vuex","vuex-class","vuex-decorators","vuex-modules"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sascha245.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-03T18:43:15.000Z","updated_at":"2025-02-28T03:02:29.000Z","dependencies_parsed_at":null,"dependency_job_id":"a4ba8eb5-dc02-4a8f-b739-291ae45dc5b6","html_url":"https://github.com/sascha245/vuex-simple","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/sascha245/vuex-simple","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sascha245%2Fvuex-simple","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sascha245%2Fvuex-simple/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sascha245%2Fvuex-simple/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sascha245%2Fvuex-simple/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sascha245","download_url":"https://codeload.github.com/sascha245/vuex-simple/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sascha245%2Fvuex-simple/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264958135,"owners_count":23689006,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["typescript","vue","vuejs","vuex","vuex-class","vuex-decorators","vuex-modules"],"created_at":"2024-12-06T17:21:29.069Z","updated_at":"2025-07-12T07:33:15.126Z","avatar_url":"https://github.com/sascha245.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# vuex-simple\n\nA simpler way to write your Vuex store in Typescript\n\n## Changelog\n\n2.0.0:\n  - Remove typedi / dependency injections: now available in a separate package [vue-typedi](https://github.com/sascha245/vue-typedi)\n  - Remove deprecated functions\n  - Cleaner and easier usages\n  - Submodules\n\n## Install\n\n1. Install vuex\n`npm install vuex --save`\n\n2. Install module:\n`npm install vuex-simple --save`\n\n## Example\n\nThis section shows how to create a simple store with *vuex-simple*.\n\n#### Module\n\nTo define our modules, we just write normal typescript classes. This means that we can use everything that would normally be possible, which also includes inheritance and generics. The decorators don't apply any logic and just store some metadata used later on by the library.\n\n```ts\n// store/modules/foo.ts\n\nimport { Mutation, State } from 'vuex-simple';\n\nexport class FooModule {\n  @State()\n  public counter: number;\n\n  constructor(nb: number = 0) {\n    this.counter = nb;\n  }\n\n  @Mutation()\n  public increment() {\n    this.counter++;\n  }\n\n  @Mutation()\n  public incrementBy(nb: number) {\n    this.counter += nb;\n  }\n\n  public async asyncIncrement() {\n    await new Promise(r =\u003e setTimeout(r, 200));\n    // call mutation function like you would any other function\n    this.increment();\n  }\n}\n```\n\n#### Submodules\n\nTo create submodules, you first create a property decorated by `@Module()` and initialize it with a new instance of your module class.\nThe module will be namespaced by the name of the property.\n\nWe can also have multiple instances of the same module if necessary. The code below would give us two submodules 'foo1' and 'foo2' with different initial values.\n\n```ts\n// store/modules/bar.ts\n\nimport { Getter, Module } from 'vuex-simple';\nimport { FooModule } from './foo';\n\nexport class BarModule {\n\n  // create submodule 'foo1'\n  @Module()\n  public foo1 = new FooModule(5);\n\n  // create submodule 'foo2'\n  @Module()\n  public foo2 = new FooModule(0);\n\n  @Getter()\n  public get total() {\n    return this.foo1.counter + this.foo2.counter;\n  }\n}\n```\n\n#### Root state\n\nWhen using submodules one might want to access the root state.\nThat's how it can be achieved:\n\n```ts\nclass ModuleA {\n  constructor(private root: RootModule) {}\n\n  @State()\n  public count: number = 0;\n\n  @Getter()\n  public get sumWithRootCount() {\n    return this.count + this.root.count;\n  }\n}\n\nclass RootModule {\n  @State()\n  public count: number = 0;\n\n  @Module()\n  public a = new ModuleA(this);\n}\n\nconst store = createVuexStore(new RootModule());\nconsole.log(store.state.a)\n# =\u003e Logs the state of `ModuleA`\n```\n\n#### Store\n\nTo create a new store, you instantiate one of your module classes and pass it to `createVuexStore`.\nThe instance is then transformed and bound to the store.\n\n```ts\n// store/store.ts\n\nimport { Module, State } from 'vuex-simple';\nimport { BarModule } from './modules/bar';\n\nexport class MyStore {\n\n  @Module()\n  public bar = new BarModule();\n\n  @State()\n  public version = \"2.0.0\";\n}\n\n// store/index.ts\n\nimport Vue from 'vue';\nimport Vuex from 'vuex';\n\nimport { createVuexStore } from 'vuex-simple';\n\nimport { MyStore } from './store';\n\nVue.use(Vuex);\n\n// create our module class instance\nconst instance = new MyStore();\n\n// create and export our store\nexport default createVuexStore(instance, {\n  strict: false,\n  modules: {},\n  plugins: []\n});\n\n// instance is now bound to the store: we can now call our mutations, getters and such as we would normally with our class instance\ninstance.bar.foo2.increment();\n\n```\n\n**Warning**: You need to create one module instance per store. Don't use an already transformed instance for `createVuexStore`.\n\n#### Usage\n\nYou can use the `useStore(store)` function to get the bound module class instance from your store.\n\n```ts\n// In your vue component\n\nimport { useStore } from 'vuex-simple';\nimport { MyStore } from '@/store/store';\nimport { FooModule } from '@/store/modules/foo';\n\n@Component\nexport default class MyComponent extends Vue {\n\n  // get the module instance from the created store\n  public store: MyStore = useStore(this.$store);\n\n  // get the module instance with the given namespace\n  public foo1?: FooModule = useModule(this.$store, ['bar', 'foo1']);\n\n  public get readState() {\n    // access state like a property\n    return this.store.version;\n  }\n\n  public get readGetter() {\n    // access getter like a property\n    return this.store.bar.total;\n  }\n\n  public commitIncrement() {\n    // call mutation like a function\n    this.store.bar.foo1.increment();\n  }\n\n  public commitIncrementBy(number: id) {\n    // call with parameter / payload\n    this.store.bar.foo2.incrementBy(10);\n  }\n\n  public callAction() {\n    this.store.bar.foo1.asyncIncrement();\n  }\n}\n```\n\n## Dynamic modules\n\nTo add a dynamic module to your store, you can use the `registerModule` function from this package:\n\n```ts\nregisterModule($store, ['dynamic_foo'], new FooModule(6));\n```\n\nYou can then use `useModule`, to get the bound class instance of the given namespace:\n\n```ts\nconst foo = useModule\u003cFooModule\u003e($store, ['dynamic_foo']);\n```\n\nTo remove the dynamic module from the store, you can use the `unregisterModule` function from this package:\n\n```ts\nunregisterModule($store, ['dynamic_foo']);\n```\n\n**Note**: You can also those functions on a standard Vuex store.\n\n## Example with dependency injections\n\nThis section shows how to use dependency injection with this library.\nIn the following examples I will be using [vue-typedi](https://github.com/sascha245/vue-typedi) that makes use of the library [typedi](http://github.com/pleerock/typedi), but you can choose any other dependency injection library if you want.\n\nNote that this step is completely optional and is in no case required for this library to work.\n\n#### Module with dependency injection\n\nYou start by decorating your class with `@Injectable`, which injects all your properties marked with `@Inject` when the class is instantiated.\n\nYou can then freely use `@Inject` in this class.\n\n```ts\n// store/modules/foo.ts\n\nimport { Mutation, State } from 'vuex-simple';\nimport { Inject, Injectable } from 'vue-typedi';\nimport { MyService } from '...';\n\n@Injectable()\nexport class FooModule {\n\n  @Inject()\n  public myService!: MyService;\n\n  ...\n}\n```\n\n#### Vue component with module injection\n\nAs dependency injection has been completely removed from this library, it is up to the user to setup and bind the values he needs in the container.\n\nIn this example, as we are using *typedi*, I will use their `Token` class to generate unique keys for our values.\nYou can then bind these keys to the appropriate values / modules in your container.\n\n```ts\n// store/tokens.ts\n\nimport { Token } from 'vue-typedi';\n\n// generate some unique keys to bind our values to\nexport default {\n  BAR: new Token(),\n  BAR_FOO1: new Token(),\n  BAR_FOO2: new Token()\n};\n\n// store/index.ts\n\nimport Vue from 'vue';\nimport Vuex from 'vuex';\nimport { Container } from 'vue-typedi';\n\nimport { createVuexStore } from 'vuex-simple';\n\nimport { MyStore } from './store';\n\nimport tokens from './tokens'\n\nVue.use(Vuex);\n\nconst instance = new MyStore()\n\n// bind tokens/keys to the appropriate module\nContainer.set(tokens.BAR, instance.bar);\nContainer.set(tokens.BAR_FOO1, instance.bar.foo1);\nContainer.set(tokens.BAR_FOO2, instance.bar.foo2);\n\nexport default createVuexStore(instance, {\n  strict: false,\n  modules: {},\n  plugins: []\n});\n\n// In your vue component\n\nimport { Inject } from 'vue-typedi';\nimport { FooModule } from '@/store/modules/foo';\nimport tokens from '@/store/tokens';\n\n@Component\nexport default class MyComponent extends Vue {\n\n  @Inject(tokens.BAR_FOO1)\n  public foo1!: FooModule;\n\n  ...\n}\n```\n\n## Decorators\n\n#### State\n\nTo tell the module which properties of the class will compose the state of the vuex module, we need to decorate those properties with `@State()`\n\n#### Getter\n\nTo add a getter, we simply write a normal getter and add a `@Getter()` decorator to it.\n\nAs with Vuex getters, they don't take any arguments. You can however pass arguments to getters by returning a function, like how it is described on the official documentations of vuex:\u003cbr/\u003e\nhttps://vuex.vuejs.org/guide/getters.html#method-style-access\n\n```ts\n// Getter\n@Getter()\npublic get numberButIncreased() {\n    return (someNumber: string) =\u003e {\n        return someNumber + 1;\n    }\n}\n\n// Usage\nmyModule.numberButIncreased(5); // returns 6\n```\n\n#### Mutation\n\nTo add a mutation, we simply write a normal function and add a `@Mutation()` decorator to it. Mutations can only have at most 1 parameter.\n\n**Note**: You can call mutations from any other function in your class, even if it is not an action.\n\n#### Action\n\nTo add an action, we simply write a normal function and add a `@Action()` decorator to it. Actions can only have at most 1 parameter.\n\n#### Module\n\nTo add submodules to your module, you can decorate a property with `@Module()`. The property name will then be used as the namespace of this module.\n\n### How to\n\n#### How to setup your store\n\n1. Use `Vue.use(Vuex)`\n\n2. Create an instance of your root module\n```ts\nconst instance = new MyStore();\n```\n\n3. Create your store. This will transform your instance so it actually uses the state, getters, mutations, etc... from the store.\n\n```ts\nconst store = createVuexStore(instance, {\n  strict: false,\n  modules: {},\n  plugins: []\n})\n```\n\n4. Your instance has been transformed and is now synchronized with the store!\n```ts\n// call a mutation\ninstance.bar.foo1.increment()\n```\n\n**Note**: You can also get the instance from the vuex store using `useStore\u003cMyStore\u003e(store)`.\n\n\n#### How to split up your modules\n\nThere are different ways to split up your modules:\n1. Do all the heavy lifting (like API requests and such) in other files or services.\n\n2. Split up your modules into multiple submodules.\n\n3. Use inheritance to split up your state, getters, mutations etc...\n\n```ts\nclass CounterState {\n  @State()\n  public counter: number = 10;\n}\n\nclass CounterGetters extends CounterState {\n  @Getter()\n  public get counterPlusHundred() {\n    return this.counter + 100;\n  }\n}\n\nclass CounterMutations extends CounterGetters {\n  @Mutation()\n  public increment() {\n    this.counter++;\n  }\n}\n\nclass CounterModule extends CounterMutations {\n  public async incrementAsync() {\n    await new Promise(r =\u003e setTimeout(r, 500));\n    this.increment();\n  }\n}\n```\n\n## Contributors\n\nIf you are interested and want to help out, don't hesitate to contact me or to create a pull request with your fixes / features.\n\nThe project now also contains samples that you can use to directly test out your features during development.\n\n1. Clone the repository\n\n2. Install dependencies\n`npm install`\n\n3. Launch samples\n`npm run serve`\n\n4. Launch unit tests situated in *./tests*. The unit tests are written in Jest.\n`npm run test:unit`\n\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsascha245%2Fvuex-simple","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsascha245%2Fvuex-simple","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsascha245%2Fvuex-simple/lists"}