Your first Vue 3 app using TypeScript
Tags: javascriptvue
Published: 2020-09-02 15:38:01

---
title: Your first Vue 3 app using TypeScript
published: true
date: 2020-08-17 13:45:56 UTC
tags: javascriptvue
canonical_url: https://www.thisdot.co/blog/your-first-vue-3-app-using-typescript
---

Vue 3 has been rebuilt from the ground up using [TypeScript](https://www.typescriptlang.org/). Since Vue2, Vue has supported TypeScript and still does. However, these days, I sense a certain hype and interest to develop Vue 3 apps using TypeScript.

Without any doubt, developing JavaScript apps using TypeScript is a life saver. TypeScript, in addition to the many goodies it brings, provides type safety. You will be happy, your IDE will be happy, and of course, it makes writing JavaScript more interesting and robust.

This article will take you on a step-by-step guide to creating a Vue 2 app, adding TypeScript support, upgrading the app to Vue 3 RC 5, compiling the app, fixing some common compile time errors, and finally make sure the app runs in the browser.

> If you’re new to TypeScript, I suggest you watch this free course [Learn TypeScript from Scratch](https://www.youtube.com/watch?v=BwuLxPH8IDs) by the distinguished [MaximilianSchwarzmüller](https://academind.com/).

> If, on the other hand, you want the source code accompanying this article, feel free to access it at this [GitHub Repo](https://github.com/bhaidar/vue-typescript).

_Disclaimer - This article applies to existing Vue 2 apps that you want to upgrade to Vue 3 and add TypeScript to the mix, and to any new app._

## Demo

Let’s start by creating a Vue 2 app, and going through the necessary steps.

### Create a New App

As the sub heading suggests, we will be creating a Vue 2 app using the Vue CLI.

##### Step 1: Install @vue/cli NPM package

Open a terminal window and run the command:

```
npm install -g @vue/cli
```

##### Step 2: Create a new Vue 2 app

```
vue create vue-ts
```

  

Select the `default preset` when prompted. The CLI scaffolds the files for you, and also initializes a Git repository for the app.

##### Step 3: Run the app

Run the app to make sure it’s working properly:

```
cd vue-ts
npm run serve
```

  

You should have a running app now!

### Add TypeScript Support

Let's run the following command to add TypeScript support to our app.

```
vue add typescript
```

  

The command above downloads and installs the [@vue/cli-plugin-typescript](https://www.npmjs.com/package/@vue/cli-plugin-typescript) plugin to bring TypeScript support to our app.

Once installed, you are asked a few questions that are shown in **Figure 1**.

[![add-typescript](https://images.ctfassets.net/zojzzdop0fzx/7wrIIZ7cpbhOAGqCrRDk21/c28582e2cc33e9c9698cee81665c4879/Screenshot_2020-08-11_at_4.27.38_PM.png)](https://images.ctfassets.net/zojzzdop0fzx/7wrIIZ7cpbhOAGqCrRDk21/c28582e2cc33e9c9698cee81665c4879/Screenshot_2020-08-11_at_4.27.38_PM.png)

  

| Installation Questions |
| --- |
| **Use class-style component syntax?** Yes |
| **Use Babel alongside TypeScript?** Yes |
| **Convert all .js files to .ts?** Yes |
| **Allow .js files to be compiled?** Yes |
| **Skip type checking of all declaration files?** Yes |

Among the many things the plugin adds to the app, I’d like to point out the `tsconfig.json` file at the root of the app folder. TypeScript uses this file to customize the compilation process, and gives you a chance to do so, to suit your needs. The settings below are recommended by the Vue team. However, feel free to add or change things as you see fit.

> For a complete list of all the options available for you to use in this file, follow this link [tsconfig.json](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html).

```
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "baseUrl": ".",
    "types": [
      "webpack-env"
    ],
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}
```

  

Finally, make sure to commit your changes to Git before moving on any further.

### Upgrade App to Vue 3

Now that the app supports writing Vue Components in TypeScript syntax, let's move on, and upgrade the app to Vue 3.

##### Step 1: Add the Vue-Next Plugin

Open a terminal window and navigate to the root folder of our app. Then, run the following command:

```
vue add vue-next
```

  

The command downloads and installs the [vue-cli-plugin-vue-next](https://www.npmjs.com/package/vue-cli-plugin-vue-next) plugin to upgrade the app to Vue 3.

**Figure 2** shows all the steps the CLI has taken to perform the upgrade.

[![add-vue-next](https://images.ctfassets.net/zojzzdop0fzx/4RRTH0TJB6S8d0aB8951gO/8c13257da1cdd2b2689b4646078c86de/Screenshot_2020-08-11_at_5.24.10_PM.png)](https://images.ctfassets.net/zojzzdop0fzx/4RRTH0TJB6S8d0aB8951gO/8c13257da1cdd2b2689b4646078c86de/Screenshot_2020-08-11_at_5.24.10_PM.png)

Open the `/package.json` file, and make sure the `dependencies` and `dev-dependencies` sections are similar to the one below:

```
 "dependencies": {
    "core-js": "^3.6.5",
    "vue": "^3.0.0-rc.5"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.4.0",
    "@vue/cli-plugin-eslint": "~4.4.0",
    "@vue/cli-service": "~4.4.0",
    "@vue/compiler-sfc": "^3.0.0-rc.5",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^7.0.0-alpha.0",
    "vue-cli-plugin-vue-next": "~0.1.3"
  },
```

  

The **vue-next** plugin automatically goes through your app files, and converts them to be compatible with Vue 3 syntax.

##### Step 2: Fix Warnings & Errors

At this point, if you compile the app, you will see some warnings and errors. These are mostly related to using TypeScript in Vue 3. Let's tackle these one by one.

Run the following command to compile and start the app in the browser:

```
npm run serve
```

  

The output is shown below:

**Warnings**

```
warning in ./node_modules/vue-class-component/dist/vue-class-component.esm.js
"export 'default' (imported as 'Vue') was not found in 'vue'

warning in ./node_modules/vue-class-component/dist/vue-class-component.esm.js
"export 'default' (imported as 'Vue') was not found in 'vue'

warning in ./node_modules/vue-class-component/dist/vue-class-component.esm.js
"export 'default' (imported as 'Vue') was not found in 'vue'

warning in ./node_modules/vue-class-component/dist/vue-class-component.esm.js
"export 'default' (imported as 'Vue') was not found in 'vue'

warning in ./node_modules/vue-property-decorator/lib/vue-property-decorator.js
"export 'default' (reexported as 'Vue') was not found in 'vue'
```

  

**Errors**

```
TS1238: Unable to resolve signature of class decorator when called as an expression.
  Type '<VC extends VueClass<any>>(target: VC) => VC' is not assignable to type 'typeof HelloWorld'.
    Type '<VC extends VueClass<any>>(target: VC) => VC' provides no match for the signature 'new (): HelloWorld'.
    33 | import { Component, Prop, Vue } from 'vue-property-decorator';
    34 | 
  > 35 | @Component
       | ^^^^^^^^^^
    36 | export default class HelloWorld extends Vue {
    37 | @Prop() private msg!: string;
    38 | }

ERROR in src/components/HelloWorld.vue:36:41
TS2507: Type 'typeof import("/Users/bhaidar/projects/vue-ts/node_modules/vue/dist/vue")' is not a constructor function type.
    34 | 
    35 | @Component
  > 36 | export default class HelloWorld extends Vue {
       | ^^^
    37 | @Prop() private msg!: string;
    38 | }
    39 | </script>
```

  

The warnings and errors show that TypeScript is not able to digest the `HelloWorld` Component that's written in the old TypeScript syntax for Vue 2. Let's refactor this component to use the latest TypeScript syntax in Vue 3.

Currently, the `/components/HelloWorld.vue` component's script block is defined as follows:

```
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';

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

  

First of all, notice the use of a `lang="ts"` attribute on the `<script>` element. This defines a TypeScript code block instead of a JavaScript code block.

Let's replace this code with:

```
<script lang="ts">
import { defineComponent } from 'vue';

export default defineComponent({
  name: 'HelloWorld',
  props: {
    msg: {
      type: String,
      required: false,
    },
  },
});
</script>
```

  

The code makes use of the new `defineComponent` global method. This method lets TypeScript properly infer types inside of the Vue Component options.

The `defineComponent` method accepts an input parameter object. It can be an Options API object or a Composition API object.

> You can read more about Options API and Composition API by checking my article on [Vue 3 Composition API, do you really need it?](https://labs.thisdot.co/blog/vue-3-composition-api-do-you-really-need-it)

Now that the `HelloWorld` component is refactored. Let’s move on, and refactor the `App.vue` component to use the new TypeScript syntax in Vue 3:

```
<script lang="ts">
import { defineComponent } from 'vue';
import HelloWorld from '@/components/HelloWorld.vue'

export default defineComponent({
  name: 'App',
  components: {
    HelloWorld
  },
});
</script>
```

  

Let's run the app by issuing the following command:

```
npm run serve
```

  

Wow! More errors and warnings!

```
Argument of type 'typeof import(\"/.../vue-ts/
node_modules/vue/dist/vue\")' is not assignable to parameters of type 'PublicAPIComponent'.

Type 'typeof import(\"/.../vue-ts/node_modules/vue/dist/vue\")' is not 
assignable to type 'ComponentOptionsWithObjectProps<any, any, any, 
any, any, ComponentOptionsMixin, ComponentOptionsMixin, EmitsOptions, 
string, Readonly<{ [x: string]: any; }> | Readonly<...>>'.
...
```

  

\_\_ Importing Vue Components\_\_

The error above is generated for Line #2 in the `main.ts` file:

```
import { createApp } from 'vue';
import App from './App.vue'
       ^^^
createApp(App).mount('#app')
```

  

Typescript, like ES 6, supports modules by using the keywords **import** and **export**. As long as you are writing your modules in TypeScript, that is, module files ending with **.ts** then you are covered.

The error above signals that TypeScript is not able to import the `App` component, as if the `App.vue` module returned is not understood by TypeScript.

The solution? Define a **shim** or **declation** file at the root folder of the app. This file has the extension of `.d.ts`. It basically makes it easier for the tooling to know how to handle `*.vue` files, also known as Single File Components (SFC).

Locate the `shim-vue.d.ts` file at the root folder of your app and replace its content with the following:

```
declare module "*.vue" {
  import { defineComponent } from "vue";
  const component: ReturnType<typeof defineComponent>;
  export default component;
}
```

  

The code declares a TypeScript module for every file ending with `*.vue` (SFC).

TypeScript will digest such a module as having the following:

- An import statement for the `defineComponent` global method
- Declaration of a `component` variable of type `defineComponent`
- Finally, a default export of the `component` variable

Having the shim file above allows TypeScript to consider any Vue Component to be a well-defined module.

##### Run the app

Now you can safely run the app knowing that it will run successfully inside the browser.

Run the following command to start the app:

```
npm run serve
```

  

Navigate to the URL `http://localhost:8080` inside your browser and you should be able to see the default home page of a newly created Vue 3 app using TypeScript, as shown in **Figure 3** below.

[![vue3-typescript-home-page](https://images.ctfassets.net/zojzzdop0fzx/1ocwf7c2QidwBZWVG3ktgQ/840662325b55c507d0a6b97cbfc1d55b/Screenshot_2020-08-11_at_10.23.14_PM.png)](https://images.ctfassets.net/zojzzdop0fzx/1ocwf7c2QidwBZWVG3ktgQ/840662325b55c507d0a6b97cbfc1d55b/Screenshot_2020-08-11_at_10.23.14_PM.png)

### Use Composition API with TypeScript

Now that the application is TypeScript-aware, let me show you how you can make use of the Composition API and type safety to define a function with typed parameters.

Replace the content of the `HelloWorld` component script with the following:

```
import { defineComponent } from 'vue';

export default defineComponent({
  name: 'HelloWorld',
  props: {
    msg: {
      type: String,
      required: false,
    },
  },
  setup(props) {
    const printMsg = (msg: string) => console.log(`The message is: ${msg}`);

    return {
      printMsg,
    };
  },
});
```

  

Notice how the code defines a new function using the Composition API with a typed parameter. The parameter is named `msg` and has a data type of `string`.

## Conclusion

Whether you are upgrading your existing Vue 2 app, or starting a new one, the article provides a step-by-step approach to adding TypeScript to the app, upgrading to Vue 3, fixing all warnings and errors, and finally running the app successfully in the browser.

This is a stepping stone in your way to build Vue 3 apps with TypeScript. The next step is to familiarize yourself more with TypeScript.

Happy Vueing!