Tutorial

How To Use TypeScript with Vue Single File Components

Updated on March 16, 2021

Developer and Author

How To Use TypeScript with Vue Single File Components

Introduction

TypeScript is a JavaScript superset created by Microsoft which turns the loosely-typed language into a strictly-typed language. It can be summarized as ECMAScript 6 with optional type declarations.

Evan You, the creator of Vue.js, has stated that Vue.js 3.0’s codebase will be rewritten entirely in TypeScript.

In this tutorial, you will use @vue/cli to generate a new Vue.js 2.0 application with TypeScript and build a Single-File Component (SFC).

Prerequisites

To follow along with this article, you will need:

This tutorial was verified with Node v15.1.0, npm v6.14.8, Vue.js v2.6.11, TypeScript v3.9.3, and @vue/cli v4.5.0.

Step 1 — Setting Up the Project

With Vue CLI 3+, it is possible to generate a new project with TypeScript already configured.

When using vue create, you will be prompted with project configurations:

Screenshot of Vue CLI prompts for picking a preset and adding TypeScript

For the purposes of this tutorial, the configuration will require:

? Please pick a preset: Manually select features

In the selection prompt, choose TypeScript:

? Check the features needed for your project: TypeScript

Answer the following prompts:

? Choose a version of Vue.js that you want to start the project with 2.x
? Use class-style component syntax? No
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfi
lls, transpiling JSX)? Yes
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No

Note: While bootstrapping a new project, you will also be prompted with: Use class-style component syntax?.

Back in February, Evan You abandoned the class style syntax for the Vue 3.0 core library altogether.

It is a popular choice, but for the purposes of this tutorial, select No.

If you would like to explore a project with class-style components, consult Writing Class-Based Components with Vue.js and TypeScript.

Selecting “TypeScript” will do several things. It will automatically add @vue/cli-plugin-typescript to your project. It will replace main.js with main.ts. It will also add shims-tsx.d.ts, and shims-vue.d.ts.

Note: If you already have a Vue project created and want to add TypeScript support to it, you can do so with the following:

  1. vue add typescript

After generating your Vue project from the command line, you might have noticed the shims-vue.d.ts file. That is the declaration file (.d.ts).

A declaration file is a file that does not contain any executable code but contains descriptions of code that exists outside of the project files.

These are useful when using Node modules that do not contain any TypeScript interfaces, types, or declaration files. In a sense, the only purpose for these files is to tell TypeScript how to handle external code.

shims.d.ts
declare module '*.vue' {
  import Vue from 'vue'
  export default Vue
}

This code essential tells the TypeScript compiler (and the IDE) how to handle .vue files.

Once you have a Vue project with TypeScript, you can configure tsconfig.json.

Step 2 — Configuring the TypeScript Compiler

You can configure TypeScript to the needs of your team or project. There are many options that you can enable or disable with the use of a tsconfig.json file. This file should live in the root directory of your project.

Feel free to experiment with these options to find which is most useful for you and your project.

noImplicitAny, noImplicitThis, noImplicitReturns are options that will likely be beneficial to most situations:

  • noImplicitAny: Raise error on expressions and declarations with an implied any type. This will throw an error if an argument, const, let, or var doesn’t have a type. This is more of a mental check on yourself to create custom data types for your code.
  • noImplicitThis: Similar to noImplicitAny but will throw an error with the this keyword. Another mental check to encourage you to type everything you can.
  • noImplicitReturns: Report an error when not all code paths in the function return a value. This helps ensure that all conditions in a given function with a return type, returns a value.

Here is an example tsconfig.json:

tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "esnext",
    "strict": true,
    "noImplicitAny": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "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"
  ]
}

More information about tsconfig.json is available in the official documentation.

Step 3 — Using Basic and Custom Data Types

In TypeScript, 12 basic types are supported:

  • boolean
  • number
  • string
  • array
  • object
  • tuple
  • enum
  • any
  • void
  • undefined
  • null
  • never

The more common types that you will be using are the primitive types: string, number, boolean, null, undefined, and void.

However, there will be times when you will need to create a custom data type. For those situations, you can create something that TypeScript calls an Interface.

In your root directory, create a directory and name it types:

  1. mkdir types

Inside this new directory, create a new file named, index.ts. You can declare a new interface with the interface keyword:

types/index.ts
export interface User {

}

Note: It is considered best practice to use CamelCase for naming conventions.

From here, you can start defining the properties and value types that the object will have.

types/index.ts
export interface User {
  firstName: string,
  lastName: string,
  twitterHandle: string,
  location: {
    city: string,
    state: string
  }
}

In this example, you have an interface with an object inside it (location). This can be broken up further by nesting interfaces.

You can also make any property optional by adding a ? to it. This means that this property may or may not have a value.

Here are the previous index.ts rewritten with those changes:

types/index.ts
export interface User {
  firstName: string,
  lastName: string,
  twitterHandle?: string,
  location: Location
}

export interface Location {
  city: string,
  state: string
}

You can now use this custom data type in any Single-File Vue Component (.vue) or TypeScript (.ts) file.

Step 4 — Using Custom Data Types in Single-File Vue Components (SFCs)

Here is an example for App.vue that uses the User interface and displays the firstName and lastName:

src/App.vue
<template>
  <p>{{ fullName }}</p>
</template>

<script lang="ts">
  export default {
    name: 'Home',
    data() {
      return {
        user: {}
      }
    },
    computed: {
      fullName() {
        return `${this.user.firstName} ${this.user.lastName}`
      }
    },
    mounted() {
      this.user = {
        firstName: `Sammy`,
        lastName: `Shark`,
        twitterHandle: `@digitalocean`,
        location: {
          city: `New York City`,
          state: `NY`
        }
      }
    }
  }
</script>

In order to use TypeScript in this component, you will need to add a lang attribute to the script tag of your component. The value of that attribute should be ts.

When using TypeScript in single-file Vue components, the Vue library must be imported so you can extend from it.

Since you will not be using the class-style syntax, you use the as keyword to declare data as a data type.

For things like const, let, var, or a function return type, you can define its type with the colon (:).

After applying these changes to App.vue, it now resembles:

src/App.vue
<template>
  <p>{{ fullName }}</p>
</template>

<script lang="ts">
  import { User } from '../types'

  export default Vue.extend({
    name: 'Home',
    data() {
      return {
        user: {} as User
      }
    },
    computed: {
      fullName(): string {
        return `${this.user.firstName} ${this.user.lastName}`
      }
    },
    mounted(): void {
      this.user = {
        firstName: `Sammy`,
        lastName: `Shark`,
        twitterHandle: `@digitalocean`,
        location: {
          city: `New York City`,
          state: `NY`
        }
      }
    }
  })
</script>

This code imports the User interface and declares reactive data as type User.

The computed property returns a string, so a string type is defined. The mounted hook returns nothing, so a void type is defined. With these definitions in place, there will be no TypeScript errors when compiling.

Compile the application:

  1. npm run serve

When you open the result in a browser, you should observe the full name displayed.

Conclusion

TypeScript is JavaScript. With TypeScript, you can be as strict or as lenient as you want. It helps keep your code base consistent and scalable as your project continues to grow.

TypeScript is also heavily integrated with various popular IDEs and editors (including VS Code, WebStorm, Sublime, Vim, Atom, and more). With these editors, TypeScript works in the background, behind the scenes to provide real-time clues, suggestions, and previews of function arguments and return types.

All-in-all, it is a language that continues to find its way into more tools, libraries, and frameworks that developers use every day. It has a strong Open Source community and the backing of Microsoft.

If you’d like to learn more about TypeScript, check out our TypeScript topic page for exercises and programming projects.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar

Developer and Author

I’m a software engineer from Cincinnati. I work on TypeScript apps with Vue.js. Currently a Senior Front-End Engineer at Enodo, based in Chicago.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
2 Comments


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Why the extension name is .vue when writing it in typescript? Is there a way to do it in proper typescript the same as angular and react typescript?

Why write

name: 'Home' as string

Isn’t ‘Home’ with quotes already enough to indicate that this value is a string?

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Featured on Community

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more