7

I am having issues trying to get Vuex with Typescript working. I did an example without typescript which worked just fine as shown first below. I am creating a Vuex module and then adding it as shown below

src -> store -> index.js

import Vue from 'vue';
import Vuex from 'vuex';
import robotsModule from './modules/products';

Vue.use(Vuex);

export default new Vuex.Store({
  modules: {
    products: productsModule
  },
});

src -> store -> modules -> products.js

import axios from 'axios';

export default {
  namespaced: true,
  state: {
    products: [],
  },
  mutations: {
    addProduct(state, product) {
      state.products.push(product);
    },
    updateProduct(state, products) {
      state.parts = products;
    },
  },
  actions: {
    getProducts({ commit }) {
      axios
        .get('/api/products')
        .then(result => commit('updateProduct', result.data))
        .catch(console.error);
    }
  },
};

Now when I want to use typescript it keeps complaining that

"Binding element 'commit' implicitly has an 'any' type."

As you can see I have currently specified the state as any which also seems wrong. How do I make this work nicely with typescript?

src -> store -> modules -> products.ts

import axios from 'axios';
import { Product } from '@/models/product';

export default {
  namespaced: true,
  state: {
    products: new Array<Product>(),
  },
  mutations: {
    updateProducts(state: any, products: Product[]) {
      state.products = products;
    },
    addProduct(state: any, product: Product) {
      state.products.push(product);
    },
  },
  actions: {
    getProducts({ commit }) {
      axios
        .get('/api/products')
        .then(result => commit('updateProducts', result.data))
        .catch(console.error);
    },
  },
};

2 Answers 2

12

I found an example online which showed that I needed to have the commit as a function

getProducts({ commit }: { commit: Function }) {

full file here

import axios from 'axios';

import { Product } from '@/models/product';
import State from '@/models/state';

export default {
  namespaced: true,
  state: {
    items: new Array<Product>(),
  } as State,
  mutations: {
    updateProducts(state: State, products: Product[]) {
      state.items = products;
    },
    addProduct(state: State, product: Product) {
      state.items.push(product);
    },
  },
  actions: {
    getProducts({ commit }: { commit: Function }) {
      axios
        .get('/api/products')
        .then(result => {
          commit('updateProducts', result.data);
        })
        .catch(console.error);
    },
  },
};

Also create a State class that I could then say is my state object

import Vue from 'vue';
import { Product } from '@/models/product';

export default class State extends Vue {
  items: Product[] = new Array<Product>();
}

Update 15-03-2021 - A work colleague of mine said he now used https://www.npmjs.com/package/direct-vuex which makes it easier!

Sign up to request clarification or add additional context in comments.

Comments

3

Building upon Andrew's answer - you can introduce a couple of interfaces to tidy up the code a little:

export interface CommitFunction {
    commit: Commit;
}

export interface CommitStateFunction<T> extends CommitFunction {
    state: T;
}

So then your action would look like:

actions: {
    getProducts({ commit }: CommitFunction) { /* logic here */ },
    updateProducts({ commit, state }: CommitStateFunction<State>) { /* logic here */ }
}

1 Comment

You need to import { Commit } from 'vuex' to avoid an error on the commit type declaration

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.