DEV Community

Fernando Alvarez
Fernando Alvarez

Posted on • Originally published at Medium on

Level Up your VueJS project with Typescript (Part 3): Vuex

If you missed part 2, go to this post:

Level Up your VueJS project with Typescript (Part 2): Translating Components to Typescript

For the complete version of this part, use this branch of the project repo:

jefer590/upgrade-vuejs-ts-series

In part 3, we translated most of our components to use Typescript using the vue-property-decorator with the exception of the View that use Vuex. In this part, we will translate our Vuex Modules and the Store.vue that uses the module. Let’s get started!

The Foo Vuex Module

If you noticed, the project already has a Vuex Module called Foo in the path ~/src/store/foo.ts. Go to that file because we are going to modify it.

Let’s take a look what’s “inside” of this simple module. The module contains a state called text which initializes a simple text string; contains a mutation to set a new text into that state; a getter to get the text string but in upper case and last the module is namespaced so, to access to this, we will need to use Foo/textUpper if we need the getter for example.

Taking all of this into account, let’s remove all the content of this file because we will rewrite the whole file in Typescript but doing the same actions and preserving the same state. For that we will use the library (installed in part 1):

championswimmer/vuex-module-decorators

Translating the Foo Vuex Module into Typescript

We will start by importing the necessary decorators and classes that we will use in the *Foo * Module:

import { VuexModule, Module, Mutation } from 'vuex-module-decorators'

In the “traditional” way, we return an object literal that contains all the states, mutations, etc; to satisfy our requirements. For this approach, we need to return a class that extends of VuexModule and the name of the class needs to be the name of the module which in this case is Foo

The only thing left to let know to Vuex that this file/class is a Module and is namespaced is use the @Module decorator at the beginning of the class and we will pass metadata to the decorator to let know this class is, in fact, namespaced:

Our Foo Module looks good but the state, mutation and getter are missing. Time to work!

To add a state to the module we will simply add a class property that needs to be public and the name of the property needs to be text and we will initialize it with the same string text as the “traditional” way:

For the mutation, we will do a class method that uses the @Mutation decorator. The name of the mutation will be defined by the name of the class method. The parameters of the class method mutation will only be the required ones to mutate the state. There’s only one catch here and is, to access to the state of this module, you will need to use this for example: this.text

And last, to create a Vuex getter, you need to define a class getter like computed properties in the Vue Component class. The name of the class getter will be the name of the Vuex getter.

https://medium.com/media/3ae7397c9f1eadd6dfd47ae0cd07fe56/href

And that’s it! if you test the project with yarn serve and see that the Store View is still working that means that the Vuex store module is using our TS implementation of it successfully 🎉

Translating Store View to Typescript

We go to ~/src/views/Store.vue and take all the part into another file because we will delete the current script content. We will define a class component following the same pattern as part 2:</p> <iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e54690ed663e61c2aa1475dc6868e83d/href">https://medium.com/media/e54690ed663e61c2aa1475dc6868e83d/href</a></iframe> <p>To create the Vuex bindings, we will use a library that I really like called vuex-class this will let us to create the bindings of our Vuex store using Decorators (already installed in part 1).</p> <p><a href="https://github.com/ktsn/vuex-class">ktsn/vuex-class</a></p> <p>In this component, we need to bind the state text, the mutation setText and the getter textUpper into it. Let’s begin!</p> <p>Since our Vuex state is inside a namespaced module, we need to create the binding for that namespace. First import:</p> <p></p> <div class="highlight"><pre class="highlight plaintext"><code>import { namespace } from 'vuex-class' </code></pre></div> <p></p> <p>Then, we will create a constant <strong>outside the class</strong> that will have the Decorators of our namespace. Using namespace as a method, you need to pass, as a parameter, the name of your namespaced vuex module so we will pass the name <em>“Foo”</em> as follows:</p> <p></p> <div class="highlight"><pre class="highlight plaintext"><code>const fooModule = namespace('Foo') </code></pre></div> <p></p> <p>Our script of that component should look like this:</p> <iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6f691ac0645ef94906f91f4d1ca58aab/href">https://medium.com/media/6f691ac0645ef94906f91f4d1ca58aab/href</a></iframe> <p>Great! time for bindings! Our first candidate is the text state. To use the namespaced state, we will use the const fooModule as decorator and the state will be a class property with the same name as the state and taking into account the proper types used in the module:</p> <p></p> <div class="highlight"><pre class="highlight plaintext"><code>@fooModule.State private text!: string </code></pre></div> <p></p> <p>Our script should look like this:</p> <iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/dad0e29ab8218c3d903c4b9cec188667/href">https://medium.com/media/dad0e29ab8218c3d903c4b9cec188667/href</a></iframe> <p>Now it’s time to bind the getter. For that, we will follow the same pattern as the state:</p> <p></p> <div class="highlight"><pre class="highlight plaintext"><code>@fooModule.Getter private textUpper!: string </code></pre></div> <p></p> <p>Our script should look like this:</p> <iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/30282cd455a3d0083dc72de46fa373c7/href">https://medium.com/media/30282cd455a3d0083dc72de46fa373c7/href</a></iframe> <p>Last but not least, it’s time to bind the mutation. We will follow the same pattern as the getter and the state BUT with a little catch in the type. The type <strong>must</strong> match the method input and output types. Fortunately, Typescript let us do this to our variables:</p> <p></p> <div class="highlight"><pre class="highlight plaintext"><code>@fooModule.Mutation private setText!: (_newText_: string) =&gt; void </code></pre></div> <p></p> <p>In this case, we are telling to the typescript compiler that this property is a method and will receive a string but it won’t return nothing by using void. After adding this, the scriptshould look like this:</p> <iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0620325c94725092402b7280d8762317/href">https://medium.com/media/0620325c94725092402b7280d8762317/href</a></iframe> <p>We are almost done! The only missing thing here is a method used in the input’s @input event method called changeText that will pass the event param with the new value and will use the mutation to change the state of text :</p> <p></p> <div class="highlight"><pre class="highlight plaintext"><code>changeText (event: _any_): _void_ { _this_.setText(event.target.value) } </code></pre></div> <p></p> <p>The script now should look like this:</p> <iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7ca1d98d2114fc18b3759d32d3f0dbec/href">https://medium.com/media/7ca1d98d2114fc18b3759d32d3f0dbec/href</a></iframe> <p>And that’s it! If we run our project with yarn serve and check again the Store view, everything should still working as expected!</p> <h4> <a name="thats-all-for-part-3-stay-tuned-for-part-four-where-we-are-going-to-create-a-new-endpoint-api-in-express-using-typescript-but-also-we-are-going-to-create-a-new-view-that-will-use-that-endpoint" href="#thats-all-for-part-3-stay-tuned-for-part-four-where-we-are-going-to-create-a-new-endpoint-api-in-express-using-typescript-but-also-we-are-going-to-create-a-new-view-that-will-use-that-endpoint" class="anchor"> </a> That’s all for part 3! Stay tuned for part four where we are going to create a new endpoint API in Express using Typescript but also we are going to create a new view that will use that endpoint. </h4> <h3> <a name="thanks-for-reading" href="#thanks-for-reading" class="anchor"> </a> 🙌 Thanks for reading! 🙌 </h3>

Latest comments (2)

Collapse
 
flozero profile image
florent giraud

i have the same probleme here

Collapse
 
_ronini profile image
Ronnie Villarini • Edited

Not sure if it's a mobile issue, but the whole second half of this post had a breakdown and is displaying as raw HTML lol