Building VueJS Applications with TypeScript
Tags: vue, typescript, frontend, javascript
Published: 2018-09-10 11:00:41

---
title: Building VueJS Applications with TypeScript
published: true
description: TypeScript has undoubtedly grown in popularity over recent years. In this guide I'll explain how to set up a VueJS application with TypeScript.
tags: vuejs, typescript, frontend, javascript
---

TypeScript has undoubtedly grown in popularity over recent years. More and more developers within the web industry are looking to use static-type languages and with the release of Angular 2 back in 2016, this has only increased the demand for developers who use TypeScript.

When I started writing Angular applications with TypeScript, I thought it was great. I liked static-type checking systems and I liked being able to store the template outside of the TypeScript file, giving me separation from the logic and presentation layers. Unfortunately, I didn't like the fact that Angular requires so much set-up and not to mention the fact you had to do three or four different things to build one component. For me, it was too costly for time.

Prior to this I had used VueJS for building single page applications and I loved it. I always wanted to be able to bring TypeScript to VueJS and so the research began!

Now I found many tutorials that explained how TypeScript could be used with VueJS, but a lot of these were focusing on single file components. Which in my opinion works with using just JavaScript, but I really liked how Angular could store the template in an HTML file.

```typescript
@Component({
    selector: 'my-dashboard',
    templateUrl: 'dashboard.component.html',
})
export class DashboardComponent {}
```

When I thought I was out of luck, I found the solution to all of my problems. The amazing VueJS team have recently released Vue CLI 3 - which has made the process of writing TypeScript applications with VueJS so much easier! Let's take a look on how to setup a VueJS application using TypeScript.

## Install Vue CLI
The first step is to install Vue CLI, to do this, simply run one of the following commands (depending on what tool you use).

```bash
npm install -g @vue/cli
# OR
yarn global add @vue/cli
```
Once this is done, you can verify that it has installed correctly by running `vue --version`. It should display something like `3.0.1`.

# Create a TypeScript project
The new Vue CLI tool allows you to easily create new projects with TypeScript. To get started, simply run `vue create my-app`. You'll then be asked to choose a preset. Using your arrow keys, choose `Manually select features`.

Next, you just need to ensure you have selected the `TypeScript` and `Babel` options. You can see below that I have also selected some other optional features.

![Select your options](https://cdn-images-1.medium.com/max/1600/1*920vRlqxtqvsKtG6XpALNQ.png "Select your options")

Once you've done this, it will ask you if you would like to use the `class-style component syntax`. You will want to choose this option.

Then configure the rest of the settings so it should look like the below image.

![Configuration options](https://cdn-images-1.medium.com/max/1600/1*y1IvrXFH4oPnuql0Vahy-g.png "Configuration options")

The Vue CLI tool will now install all of the dependencies and set the project up.

## Add Extra Dependencies
To achieve the affect we are after, there are a few extra dependencies that we need to install. You can install these by running one of the following commands.

```bash
npm install --save vue-template-loader webpack-stream
# OR
yarn add vue-template-loader webpack-stream
```

You should now be able to run `yarn serve` to view your current application.

## Using TypeScript classes instead of Single File Components
Next, we want to remove the need for `.vue` files and instead use TypeScript classes. Within the `components` directory, you can see there is `HelloWorld.vue`. We are going to re-create this with a TypeScript class instead.

So firstly, create a new file within the `components` directory and call it `HelloWorld.ts`. We'll add the following boilerplate to get started.

```typescript
import { Component, Vue } from 'vue-property-decorator';

@Component
export default class HelloWorld extends Vue {

}
```

This gives us a blank component ready to use. The first thing we need to do is have an external `.html` file for our presentation layer of the component. To do this, create a new file called `hello-world.html`. You can place this file wherever you want, but for demonstration purposes I will place it in the same folder as our component.

Now we need to copy across the presentation from the `HelloWorld.vue` component into our new `hello-world.html` file. So our file should now look like this.

```html
<div class="hello">
    <h1>{{ msg }}</h1>
    <p>
      For guide and recipes on how to configure / customize this project,<br>
      check out the
      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
    </p>
    <h3>Installed CLI Plugins</h3>
    <ul>
      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-typescript" target="_blank" rel="noopener">typescript</a></li>
    </ul>
    <h3>Essential Links</h3>
    <ul>
      <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
      <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
      <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
      <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
      <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
    </ul>
    <h3>Ecosystem</h3>
    <ul>
      <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
      <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
      <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
      <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
    </ul>
  </div>
```

So how do we use this template file within our `HelloWorld.ts` class? The extra dependencies we installed enable us to use another decorator, `WithRender`. This allows us to import our HTML file and tell our Vue component to use our file for rendering. After adding this to our TypeScript file, it should look like this.

```typescript
import { Component, Vue } from 'vue-property-decorator';
import WithRender from './hello-world.html';

@WithRender
@Component
export default class HelloWorld extends Vue {

}
```

Now we need to hook up the Vue Router to use our new TypeScript class instead of the `HelloWorld.vue` file. To do this, open the `views/Home.vue` file. Realistically you would also create a TypeScript class for this component as well, but for this guide, we will just edit it.

Within the file, change the import statement to use our TypeScript file instead. So we will change the following line from
```typescript
import HelloWorld from '@/components/HelloWorld.vue'
```

to

```typescript
import HelloWorld from '@/components/HelloWorld.ts';
```

However, if you now go to your browser, you will see there is an error. In our terminal we get the error:
```bash
Cannot find module './hello-world.html'
```

This is because TypeScript doens't know how to handle `.html` files. So we need to add a `shim` file. To do this, within the `src` folder, create a `shims-html.d.ts` file. Paste the following code so your file should look like this:

```typescript
declare module '*.html' {
    import Vue, { ComponentOptions, FunctionalComponentOptions } from 'vue'
    interface WithRender {
        <V extends Vue, U extends ComponentOptions<V> | FunctionalComponentOptions>(options: U): U
        <V extends typeof Vue>(component: V): V
    }
    const withRender: WithRender
    export default withRender
}
```

Now we need to update our `tsconfig.json` file so that TypeScript knows to load `.html` files. Add the following line to the `include` array: `"src/**/*.html"`. So it should look something like this:

```json
  ...
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx",
    "src/**/*.html"
  ],
  ...
```

Finally, we need to add some custom webpack configuration in the build process to tell Vue to pass the html file through its template compiler. To do this, within the root of your project create a `vue.config.js` file and add the following:

```javascript
module.exports = {
  configureWebpack: {
    module: {
      rules: [
        {
          test: /.html$/,
          loader: "vue-template-loader",
          exclude: /index.html/
        }
      ]
    }
  }
}
```

Next, we need to restart the compilation process so TypeScript loads our changes. Close the current terminal process and run one of the following commands again.

```bash
npm run serve
# OR
yarn serve
```

You should now see the application loading as it was before, this time it is using the TypeScript class file and the html template file.

One last thing you might notice is that the `msg` data property is no longer there. So let's add that now.

Within your `HelloWorld.ts` file, add the following property

```typescript
public msg: string = 'I am using TypeScript classes with Vue!';
```

If you now look back at your browser, you should now see this being rendered on the page.

That's all there is to it, you can now build your application using Vue, but using TypeScript classes and `html` file templates. While some people may disagree with this approach and argue you should only use `.vue` files, I find this
approach cleaner, especially when some of the files get really long.

This is the first part in a series. Next time I will go deeper into writing VueJS applications with TypeScript and explain methods, data attributes, props, child components and more!

## UPDATE

Part two is now available - [https://dev.to/georgehanson/building-vue-js-applications-with-typescript-part-two-2808](https://dev.to/georgehanson/building-vue-js-applications-with-typescript-part-two-2808)