Writing Vue.js Apps with TypeScript
Tags: vue, typescript, webdev, javascript
Published: 2021-01-23 20:05:48

**Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62**

**Subscribe to my email list now at http://jauyeung.net/subscribe/**

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at how to write Vue.js apps with TypeScript.

Support for TypeScript
======================

Vue.js has built-in support for TypeScript. It provides us with a mostly static type system that reduces the chances for run-time errors in our code.

Vue ships with official type declarations for TypeScript. It’s included in Vue, Vue Router and Vuex.

TypeScript can resolve types declarations in NPM packages, so we don’t have to worry about them resolving them ourselves.

Using Vue CLI
=============

We can use the Vue CLI to create a Vue TypeScript project. To do this, we have to run Vue CLI by running:

```
npx vue create .
```

in our project directory.

Then we select ‘Manually select features’ and then TypeScript. The rest can stay with the default options.

Then we run `npm run serve` to run the project hot reload.

If we want, we can also set the following recommended options in `tsconfig.json` :

```
{  
  "compilerOptions": {  
    "target": "es5",  
    "strict": true,  
    "module": "es2015",  
    "moduleResolution": "node"  
  }  
}
```

`target` is the build target. Setting it to `es5` maximizes support for browsers.

`strict` enables or disables strict type check. Setting it to `true` will enable it.

`“module”: “es2015”` leverage tree shaking capabilities of Webpack 2+ or Rollup to reduce bundle size and speed up loading.

Defining and Using Components
=============================

We can define components by using the class syntax. For example, with the TypeScript project that we created with Vue CLI, we can do this as follows:

`src/components/Message.vue` :

```
<template>  
  <div class="hello">  
    <h1>{{ msg }}</h1>  
  </div>  
</template><script lang="ts">  
import { Component, Prop, Vue } from 'vue-property-decorator';

@Component 
export default class Message extends Vue {  
  @Prop() private msg!: string;  
}  
</script>
```

In the code above, we have the `@Prop` decorator to define the `message` prop. The exclamation mark after `msg` makes `msg` required. To the right of the colon, we have the type of the prop, which is a string.

`src/App.vue` :

```
<template>  
  <div id="app">  
    <input v-model="message">  
    <Message :msg="message"/>  
    <button @click="showMessage">Show Message</button>  
  </div>  
</template>

<script lang="ts">  
import { Component, Vue } from 'vue-property-decorator';  
import Message from './components/Message.vue';

@Component({  
  components: {  
    Message,  
  },  
})  
export default class App extends Vue {  
  message: string = ''; showMessage(): void{  
    alert(this.message)  
  }  
}  
</script><style>  
#app {  
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif  
}  
</style>
```

In the code above, we defined the `message` field, which is bound to the template with `v-model` .

We also have a `showMessage` method that’s run when the Show Message button is clicked.

Then we can see an input box where we can type things in. What we type will show in below the input box in the `Message` component, and when we click Show Message, we get what we typed is shown in the alert box.

Use Vue.extend to Create Components
===================================

We can also use `Vue.extend` to create components.

For example, we can replace `src/components/Message.ts` with the following”

```
import Vue, { VNode } from 'vue'
const Component = Vue.extend({  
  props: ['msg'],  
  computed: {  
    greeting(): string {  
      return `Hi. ${this.msg}`;  
    }  
  },  
  render(createElement): VNode {  
    return createElement('div', [  
      createElement('p', this.msg),  
      createElement('p', this.greeting),  
    ])  
  }  
})export default Component;
```

In the code above, we render a `div` with the `msg` prop and `greeting` computed property.

Note that we have `VNode` return type for `render` . This will ensure that we return the right type of data. TypeScript can’t infer types in many cases.

Since we use `Vue.extend` , we’ll get type inference and autocomplete.

We have to export by writing:

```
export default Component;
```

so that it’ll be available to other components.

Then we can import it as usual in `src/App.vue` :

```
<template>  
  <div id="app">  
    <input v-model="message">  
    <Message :msg="message"/>  
    <button @click"showMessage">Show Message</button>  
  </div>  
</template><script lang="ts">  
import { Component, Vue } from 'vue-property-decorator';  
import Message from './components/Message';

@Component({  
  components: {  
    Message,  
  },  
})  
export default class App extends Vue {  
  message: string = ''; showMessage(): void{  
    alert(this.message)  
  }  
}  
</script><style>  
#app {  
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif  
}  
</style>
```

Then we the input where we can type in something and it’ll show up with and without `Hi` added before it.

We keep the Show Message button acting the way before.

Augmenting Types for Use with Plugins
=====================================

We can add our own properties to existing types by writing the following:

```
import Vue from 'vue'declare module 'vue/types/vue' {  
  interface Vue {  
    $myProperty: string  
  }  
}
```

The code above imports Vue and then add the `$myProperty` string property as a valid property.

This should make TypeScript compiler be aware of the code and it should compile successfully.

Conclusion
==========

We can create a new project with TypeScript by using the Vue CLI. To do this, we choose Manually Select Features and then TypeScript. We can keep the default option for the rest or we can choose what we want if we know we want it.

To get type inference and autocomplete, we can define components with the `Vue.extend` method or define it as a class.

We can augment existing Vue types by using the `declare module` syntax and adding what we want inside it.

TypeScript can’t infer return types of functions in many cases. Therefore, we should annotate the return type so that we get autocomplete and type checking.