Type Vue without TypeScript

Type Vue without TypeScript
A practical guide for type checking Vue components written in JS and getting things done.

Why do we need types?

In the last decade, browsers have become very powerful, allowing developers to build rich interactive applications. The interactivity and richness have come with an increase in complexity and size of the codebase in the frontend. Large complex codebases demand more attention and frontend teams have become larger.

When more than one developer collaborates, there is a requirement of clear interfaces and APIs. JavaScript is very flexible, but you cannot deduce the type of arguments a function would accept.

e.g., What do you think print function’s argument type is?

function print(value) {
  console.log(value)
}

The type of value is ambiguous, even after looking at the source code of the print function which poses problems in large codebases where you cannot afford to jump into the source to deduce argument type of a function. One way to resolve this issue is to document the function’s API, but docs have a tendency of getting outdated.

What if there were a way to know a function’s argument types by just glancing over the function name?

Yes, there is a way: types or TypeScript.

function print(value: string) {
  console.log(value)
}

As soon as we look at the print function, we know value should be a string. That little information immediately boosts collaboration and productivity.

In some sense, types make APIs self-documenting. Apart from this, code editors/IDEs also benefit a lot from types. IDEs can provide intelligent suggestions, and display type mismatches inline.

Any application that can be written in J̶a̶v̶a̶S̶c̶r̶i̶p̶t̶ TypeScript, will eventually be written in J̶a̶v̶a̶S̶c̶r̶i̶p̶t̶ TypeScript.
_ — _J̶e̶f̶f̶ ̶A̶t̶w̶o̶o̶d̶ Rahul Kadyan

So TypeScript is it?

TypeScript makes interfaces explicit and enables collaboration, but it comes with its complexity and downsides.

  • Additional time would be spent adding types.
  • JavaScript’s flexibility is lost as we have to type everything and sometimes it gets very complicated to add types.
  • A steep learning curve and retraining of developer staff.

Vue and TypeScript

Vue provides a fluent object-based API for authoring composable components.

Todo.js

export default {
  data() {
    return {
      items: []
    }
  },
  methods: {
    add(text) {
      this.items.push({ text, done: false })
    },
    complete(index) {
      this.items[index].done = true
    }
  }
}

The above component can be written in TypeScript as:

Todo.ts

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

interface TodoItem {
  text: string
  done: boolean
}

@Component
export default class Todo extends Vue {
  private items!: TodoItem[]

  private add(text: string) {
    this.items.push({ text, done: false })
  }

  private complete(index: number) {
    this.items[index].done = true
  }
}

With TypeScript, you get type based intellisense which boosts developer productivity.

TypeScript support in Vue was an afterthought, and it becomes quite verbose in real-world applications. Good thing is that’s going to change with Vue 3 coming mid-next year.

Adding types to Vuex is even more complex and unpleasant. Also, the intellisense on state/getter/actions mapped to components is almost non-existent.

Most common bugs in Vue apps are not due to type errors.
 — Chris Fritz, Curator of Vue Docs

Yes, that’s true, and tools like ESLint are far more helpful in catching these bugs.

So, do we need TypeScript at all?

Maybe but you don’t need to jump on it today. TypeScript ensures type safety, documents API interfaces and enables intellisense in IDEs. I feel intellisense is far more critical in Vue application projects than type safety.

The best thing about TypeScript is that you can take advantage of TypeScript without using TypeScript.

Yes, with VS Code and TypeScript, we can get intellisense in JavaScript files. We can enforce type safety too if we want that. VS Code infers JSDoc annotations to generate TypeScript definition on the fly. Let’s set up a JavaScript project with types and intellisense.

Intellisense in JavaScript

In JavaScript files, VS Code infers types for static values to provide intellisense, including object property names, function return value type, and property types.

VS Code has automatic type acquisition which uses npm package’s bundled types or community types from DefinitelyTyped to provide intellisense, including method signature and parameter info. Also, using Vue’s type information and Vetur plugin, it can provide rich completions and type information in .vue files too.

However, static type inference for array literals and dynamic values is not possible, for such cases, VS Code can use JSDoc annotations to collect type information. In the following snippet, type of this.items is detected as an array of type any, as it’s known statically that this.items is an array, but there is no information about values in the array. We can use a@type annotation for adding type information to this.items, @type allows adding type information, similar to any typed language (or TypeScript).

VS Code type inference from JSDoc comments is as reasonable as TypeScript. See the following code snippets written in JavaScript and TypeScript.

Using JSDoc to add type information to Vue components

Vue component options have data, props, computed and methods which when provided with type information can significantly improve the developer experience.

1\. Data

We have to provide @type annotations for properties which are impossible infer statically. e.g.:

In the above snippet, items and currentItem have incomplete type information, so we need@type annotations only for those two properties.

Type definitions for items and currentItem are quite similar. If we were writing TypeScript, we would have created an interface for the item type. With JSDoc, we can define custom types or interfaces using a@typedef annotation.

Autocomplete suggestions and type information for data are available on this context in life-cycle hooks, methods, computed and watch handlers.

2. Props

For primitive props, VS Code can infer type information automatically.

However, if you have Object or Array as the type, then auto-inferred type information is useless. In such cases, we have to provide type information with a @type annotation.

It even works with the validator options syntax for props.

When defining prop names as an array, it’s a little complex to provide type information. It is discouraged to use names array for props definition.

3. Computed

For computed properties, automatic return type inference does not work as expected but it does provide computed property names in suggestions.

So with a @returns annotation, we can provide type information for the returned value as well.

4. Methods

Method names are available in VS Code suggestions on this context, but they lack type information.

Here, we see the add method accepts one parameter text and returns a number, the auto inferred information is already beneficial, and if we can provide type information for the text parameter, we get the complete experience of a typed language. Moreover, we can add types to parameters using the @param annotation.

We can even provide a small description of the method if it’s not clear from its name.

VS Code supports even more JSDoc annotations; you can find the complete list of supported annotations on the VS Code wiki page.

Can we do strict type checks in JavaScript?

Yes, it’s possible, add // @ts-check at the start of the script in .vue file.

If you want to enable strict type checks in the whole project, then you should add a jsconfig.json file to the project root.

{
  "compilerOptions": {
    "checkJs": true
  }
}

You can find more options at the [jsconfig.json](https://code.visualstudio.com/docs/languages/jsconfig) reference.

Learn more

Learn Web Development Using VueJS

Learn by Doing: Vue JS 2.0 the Right Way

Vue.js 2 Essentials: Build Your First Vue App

Getting started with Vuejs for development

Horizontal Feed Component with Sass and VueJs 2

Suggest:

Vue js Tutorial Zero to Hero || Brief Overview about Vue.js || Learn VueJS 2023 || JS Framework

Getting Started with Python in Visual Studio Code | Python with VSCode

Is Vue.js 3.0 Breaking Vue? Vue 3.0 Preview!

Learn Vue.js from scratch 2018

Vue.js Tutorial: Zero to Sixty

Learn Vue.js from Scratch - Full Course for Beginners