@simpli/vuex-typescript
TypeScript icon, indicating that this package has built-in type declarations

1.0.0 • Public • Published

Vuex Typescript Accessor

An effective accessor to make Vuex 100% typescript friendly

Install

npm i @simpli/vuex-typescript vuex

Configuration with example

The example below is a Vuex Store scenario which has the RootStore with a module called BasketModule

src/store/index.ts

import Vue from 'vue'
import Vuex, {Store} from 'vuex'
import {RootStore} from '@/store/RootStore'
import {BasketModule} from '@/store/modules/BasketModule'

Vue.use(Vuex)

export const root = new RootStore()
export const basket = new BasketModule()

root.modules = {
  basket,
}

export new Store(root)

src/store/RootStore.ts

import {AccessorHandler} from '@simpli/vuex-typescript'
import {ActionContext, ModuleTree, StoreOptions} from 'vuex'

export interface RootState {
  language: string
}

export type RootContext = ActionContext<RootState, RootState>

@AccessorHandler
export class RootStore implements StoreOptions<RootState> {
  modules?: ModuleTree<RootState>

  state: RootState = {
    language: 'en-US',
  }

  getters = {
    language: (state: RootState) => state.language,
  }

  actions = {
    changeLanguage(context: RootContext, language: string) {
      context.commit('SET_LANGUAGE', language)
    },
  }

  mutations = {
    SET_LANGUAGE(state: RootState, val: string) {
      state.language = val
    },
  }
}

src/store/modules/BasketModule.ts

import {AccessorHandler} from '@simpli/vuex-typescript'
import {ActionContext, Module} from 'vuex'
import {RootState} from '@/store/RootStore'
import {BasketItem} from '@/models/BasketItem'

export type BasketContext = ActionContext<BasketState, RootState>

export interface BasketState {
  items: BasketItem[]
}

@AccessorHandler
export class BasketModule implements Module<BasketState, RootState> {
  namespaced = true

  state: BasketState = {
    items: [],
  }

  getters = {
    isEmpty: (state: BasketState) => !state.items.length,
    items: (state: BasketState) => state.items,
    amount: (state: BasketState) => state.items.reduce((a, b) => a + (b.price || 0), 0),
  }

  actions = {
    async addItem(context: BasketContext, item: BasketItem) {
      context.commit('PUSH_ITEM', item)
    },

    async removeItem(context: BasketContext, item: BasketItem) {
      context.commit('REMOVE_ITEM', item)
    },

    async clearBasket(context: BasketContext) {
      context.commit('SET_ITEMS', [])
    },
  }

  mutations = {
    PUSH_ITEM(state: BasketState, item: BasketItem) {
      state.items.push(item)
    },

    REMOVE_ITEM(state: BasketState, item: BasketItem) {
      const index = state.items.indexOf(item);
      if (index >= 0) {
        state.items.splice(index, 1);
      }
    },

    SET_ITEMS(state: BasketState, items: BasketItem[]) {
      state.items = items
    },
  }
}

src/models/BasketItem.ts

export class BasketItem {
  constructor(
    public id: number | null = null,
    public name: string | null = null,
    public price: number | null = null,
  ) {}
}

src/helpers/App.ts

import {AccessorWrapper} from '@simpli/vuex-typescript'
import {RootState} from '@/store/RootStore'
import {store, root} from '@/store'

export const wrapper = new AccessorWrapper<RootState, RootState>()

export abstract class App {
  $read = wrapper.accessors.read
  $dispatch = wrapper.accessors.dispatch
  $commit = wrapper.accessors.commit

  get language() {
    return App.$read(root.getters.language)(store)
  }

  changeLanguage(language: string) {
    return App.$dispatch(root.actions.changeLanguage)(store, language)
  }
}

src/helpers/Basket.ts

import {AccessorWrapper} from '@simpli/vuex-typescript'
import {RootState} from '@/store/RootStore'
import {BasketState} from '@/store/modules/BasketModule'
import {BasketItem} from '@/models/BasketItem'
import {basket} from '@/store'

export const wrapper = new AccessorWrapper<BasketState, RootState>('basket')

export abstract class Basket {
  $read = wrapper.accessors.read
  $dispatch = wrapper.accessors.dispatch
  $commit = wrapper.accessors.commit

  get isEmpty() {
    return Basket.$read(basket.getters.isEmpty)(store)
  }

  get items() {
    return Basket.$read(basket.getters.items)(store)
  }

  get amount() {
    return Basket.$read(basket.getters.amount)(store)
  }

  addItem(item: BasketItem) {
    return Basket.$dispatch(basket.actions.addItem)(store, item)
  }

  removeItem(item: BasketItem) {
    return Basket.$dispatch(basket.actions.removeItem)(store, item)
  }

  clearBasket() {
    return Basket.$dispatch(basket.actions.clearBasket)(store)
  }
}

src/types/vue.d.ts

import {App} from '@/helpers/App'
import {Basket} from '@/helpers/Basket'

declare module 'vue/types/vue' {
  interface Vue {
    $app: typeof App
    $basket: typeof Basket
  }
}

src/main.ts

import Vue from 'vue'
import {App} from '@/helpers/App'
import {Basket} from '@/helpers/Basket'

// ...

Vue.prototype.$app = App
Vue.prototype.$basket = Basket

// ...

Usage in Typescript/JS file

import {Root} from '@/helpers/Root'

console.log(Root.language) // en-US

Root.changeLanguage('pt-BR')

console.log(Root.language) // pt-BR
import {Basket} from '@/helpers/Basket'
import {BasketItem} from '@/models/BasketItem'

const items = Basket.items

console.log(items) // []
console.log(Basket.isEmpty) // true
console.log(Basket.amount) // 0

const item1 = new BasketItem(1, 'foo', 10)
const item2 = new BasketItem(2, 'bar', 20)
const item3 = new BasketItem(3, 'foobar', 30)

Basket.addItem(item1)
Basket.addItem(item2)
Basket.addItem(item3)

console.log(items) // [item1, item2, item3]
console.log(Basket.isEmpty) // false
console.log(Basket.amount) // 60

Basket.removeItem(item2)

console.log(items) // [item1, item3]
console.log(Basket.isEmpty) // false
console.log(Basket.amount) // 40

Basket.clearBasket()

console.log(items) // []
console.log(Basket.isEmpty) // true
console.log(Basket.amount) // 0

Usage in Vue file

<template>
  <div>
    <div>
      Current language:
      {{ $app.language }}
    </div>

    <button @click="$app.changeLanguage('pt-BR')">
      Change Language
    </button>
  </div>
</template>

<script lang="ts">
import {Component, Vue} from 'vue-property-decorator'

@Component
export default class MyComponent extends Vue {}
</script>

Credit

This library was built based on this repository https://github.com/istrib/vuex-typescript

Package Sidebar

Install

npm i @simpli/vuex-typescript

Weekly Downloads

5

Version

1.0.0

License

MIT

Unpacked Size

41.6 kB

Total Files

22

Last publish

Collaborators

  • joao.lippi
  • mrlopz
  • melanke