# Type Safety
WARNING
Everything shown below assumes that you passed the final store to config.store
. You can see how it is done here.
# How to use it
When using the default way of accessing the vuex store, you never know eg. what type the getter returns or what payload the action accepts. Thats why we automatically create static properties on every vuex module you create and pass through the ExportVuexStore
function. Before we are ready to access the static properties, we need to pass the class to the getModule
function, which returns the static properties.
First we need a basic vuex module.
import { VuexClass, VuexModule, Action, HasGetterAndMutation } from '@averjs/vuex-decorators';
import axios from 'axios';
@VuexClass
export default class TestStore extends VuexModule {
private moduleName = 'test';
@HasGetterAndMutation test = 'test';
@Action async fetchSomething({ data }) {
const { data: { test } } = await axios({
url: `test`,
method: 'GET',
data
});
this.$store.commit('test', test);
}
}
What happens internally is that the @VuexClass
decorator modifies the class by defining all the decorated properties and methods as static properties. For example the fetchSomething
action is assigned as a static fetchSomething
method which calls config.store.dispatch('test/fetchSomething')
and returns a promise. We can now use our module like this.
<template>
<div>{{ test }}</div>
</template>
<script type="ts">
import { Vue, Component } from 'vue-property-decorator';
import TestStore from './TestStore';
import { getModule } from '@averjs/vuex-decorators';
const TestModule = getModule(TestStore);
@Component
export default class Test extends Vue {
get test() {
// old way
return this.$store.getters['test/test'];
// new way
return TestModule.test;
}
set test(val) {
// old way
this.$store.commit('test/test', val);
// new way
TestModule.test = val;
}
async callAction() {
const data = new FormData();
// old way
await this.$store.dispatch('test/fetchSomething', { data });
// new way
await TestModule.fetchSomething({ data });
}
}
</script>
This feature is not limited to Typescript. It can also be used with Babel. Even though it will not give you precise typings, your IDEs intellisense will still tell you what can be called inside your vuex module.
# this
context
In the example above, you can see that inside the action, in order to mutate a state, we used this.$store
. This eliminates typings and can be prone to errors. To make DX even better, you can call every action, mutation, ... by using this
, like you would do in a normal class. This also works with nested stores. The example above could look something like this.
import {
VuexClass,
VuexModule,
Action,
HasGetterAndMutation,
Nested,
Mutation,
Getter
} from '@averjs/vuex-decorators';
import axios from 'axios';
@VuexClass
class NestedStore extends VuexModule {
private moduleName = 'nested';
nestedState = 'nested';
get lazyNestedState() { return this.nestedState; }
}
@VuexClass
export default class TestStore extends VuexModule {
private moduleName = 'test';
@Nested() nested = new NestedStore();
@HasGetterAndMutation test = 'test';
get lazyTest() { return this.test }
set lazyTest(val) { this.test = val; }
@Getter getTest() {
return this.test;
}
@Mutation setTest(val) {
this.test = val;
}
@Action async anotherAction() {
this.setTest('hello');
console.log(this.getTest());
this.lazyTest = 'world';
console.log(this.lazyTest);
console.log(this.nested.lazyNestedState);
}
@Action async fetchSomething({ data }) {
const { data: { test } } = await axios({
url: `test`,
method: 'GET',
data
});
this.test = test;
await this.anotherAction();
}
}
You can see that everything is callable as it was defined. Eg. the @Getter
was defined as a function and can be called like that.
One thing you still have to keep in mind is that we still follow the recommended vuex way. That means you can only call the stuff that would be passed as context.
For getters
:
- state
- getters
For actions
:
- state
- mutations
- getters
- actions
# root access
actions
and getters
both are having access to rootState
and rootGetters
. When you decide you want to go with the complete Type Safe
way and also not using this.$store
inside the module classes, it would be a bummer if you would have to use this.$store
only to access root stuff. To solve that problem, you dont need to learn anything new, just import the store classes you passed through the getModule
function and call it inside your actions or wherever you want.
import { VuexClass, VuexModule, HasGetterAndMutation, getModule } from '@averjs/vuex-decorators';
import axios from 'axios';
@VuexClass
export default class AnyStore extends VuexModule {
private moduleName = 'anyStore';
@HasGetterAndMutation test = 'hello world';
}
export const AnyModule = getModule(AnyStore);
import { VuexClass, VuexModule, Action, HasGetterAndMutation } from '@averjs/vuex-decorators';
import { AnyModule } from './AnyStore';
@VuexClass
export default class TestStore extends VuexModule {
private moduleName = 'test';
@HasGetterAndMutation test = 'test';
@Action async fetchSomething() {
this.test = AnyModule.test;
}
}
← Nested