Start with Vue 2 + Vuex 3 + Typescript Simple Boilerplate

Introduction

If you read this post, you may have already heard that Vue 2 is not for TypeScript, but for Vue 3 is.
However, Vue 2 is almost 90% of the Vue framework in the world. Furthermore, even today, jQuery and Angular are still dominating the web, and it is like a moon to the users who migrate to React or Vue from the legacy framework. Even more, migrate to Vue 3?
My answer is not yet. Vue 3 is still not practically supported by many 3rd-parties. For example, there is a big difference in support volume from Vue 2 and Vue 3 from one of the most famous design-framework for Vue, Vuetify.
Of course, Vue 3 is a better framework for modern web development, especially for TypeScript, which is almost standard for all web development. Vue 3 will replace the Vue 2 eventually in the future.
However, for now, Vue 3 is still questionable about stability and compatibility compare to Vue 2. Therefore, there are a lot of users who stick to Vue 2 with JavaScript, even they want to use TypeScript. As one of them, I would like to introduce how I apply TypeScript with Vuex to my Vue 2 framework in this post.

1. Use Vue-Cli

Fortunately, vue-cli already support the option to choose for custom option for TypeScript.
Create any folder for project then run vue-cli start command below.

$ mkdir vue2ts // create project folder

$ cd vue2ts // get inside the folder

$ vue create . // vue-cli run

//////////////////////// Vue Cli Options //////////////////////////

? Generate project in current directory? (Y/n) // Y

? Please pick a preset: // > Manually select features

? Check the features needed for your project: // [ Choose Vue version, TypeScript, Vuex ]

? Choose a version of Vue.js that you want to start the project with (Use arrow keys) // 2.x

? Use class-style component syntax? // you can choose any

? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? // y

? Where do you prefer placing config for Babel, ESLint, etc.? // In dedicated config files

2. Project Tree Setup

First and foremost, Set the project folder tree. Generate files and put them like below before starting to check details.
If there is no description, leave them as they are.

.
├── public
├── src/
│   ├── assets
│   ├── components/
│   │   ├── HelloWorld.vue
│   │   ├── HelloWorld.type.ts
│   │   └── HelloWorld.slice.ts
│   └── store/
│       ├── index.ts
│       └── reducers.ts
├── App.vue
├── main.ts
└── ...

3. Vuex Setup

Let’s set up the Vuex.
Recently, I prefer the slice concept for managing global state more than using dedicate reducer folder.
there are number of better way or taste to use global state, don’t be stressed out from my approach for it. it is just one option of them.

  1. Generate the global state module as a slice for main page in HelloWorld.slice.ts.

src/components/HelloWorld.slice.ts

import { HelloWorldSlice } from '@/components/HelloWorld.type';

const state = (): HelloWorldSlice => ({
	helloSlice: [
		{ title: 'first', image: 'https://picsum.photos/100' },
		{ title: 'second', image: 'https://picsum.photos/101' },
		{ title: 'third', image: 'https://picsum.photos/99' },
	],
});

const mutations = {
	// mutation: this doesn't use in this post
};

const actions = {
	// actions: this doesn't use in this post
};

const getters = {
	// getters: this doesn't use in this post
};

export default {
	namespaced: true,
	state,
	mutations,
	getters,
	actions,
};
  1. Generate types for slice in HelloWorld.type.ts

src/components/HelloWorld.type.ts

export interface HelloWorldSlice {
	helloSlice: HelloSlice[];
}

export interface HelloSlice {
	title: string;
	image: string;
}
  1. Collect & Export slice and type of HelloWorld component in reducer.ts

src/store/reducer.ts

export { default as helloWorldSlice } from '@/components/HelloWorld.slice';
export * from '@/components/HelloWorld.type';
  1. Final setup for the Vuex.

src/store/index.ts

import Vue from 'vue';
import Vuex from 'vuex';
import { helloWorldSlice, HelloWorldSlice } from './reducers';

export interface State {
	helloWorldSlice: HelloWorldSlice;
}

Vue.use(Vuex);

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

4. Apply Global State to Vue component

Last but not least, applying global state to local component. I am going to use helper for this.
Of course, you can directly access use by this.$store.

src/components/HelloWorld.vue

The point is Vue Constructor. Without this, it never automatically shows the method or key in the Vue script.
Plus, mapState('module-name', ['state-name']) does not support type automation either, so that we have to call global state following this code: mapState('module-name', { 'state-name' : state => (state as module-state-type).state-name }). It works for the type automation in the Vue template.

script
<script lang="ts">
import Vue, { VueConstructor } from 'vue';
import { mapState } from 'vuex';
import { HelloWorldSlice, HelloSlice } from './HelloWorld.type';

interface VuexBindings {
	helloSlice: HelloSlice;
}

export default (Vue as VueConstructor<Vue & VuexBindings>).extend({
	name: 'HelloWorld',

	computed: {
		...mapState('helloWorldSlice', {
			helloSlice: (state) => (state as HelloWorldSlice).helloSlice,
		}),
	},
});
</script>
template
<template>
	<section>
		<div v-for="(hello, index) in helloSlice" :key="index">
			<div>{{ hello.title }}</div>
			<img :src="hello.image" alt="hello-images" />
		</div>
	</section>
</template>

Conclusion


type-vuex-result

This is what you get in this post.
Even though it needs some additional code for applying type with Vuex, it’s very simple to use, right? I hope it could give a hint for someone who struggling apply TypeScript to your Vue 2 project.