A guide to using TypeScript in Vue, with maximal VSCode IntelliSense

As a lover of TypeScript InteliSense and Vue, I have always tried to use TypeScript in Vue, but Vetur isn't as smart as it should…

So, I have found some fixes --

After, vue create <APP_NAME>

  • Change src/App.vue to src/pages/App/index.(tsx|css)
  • Change components/HelloWorld.vue to src/components/HelloWorld/index.(tsx|css)
  • Change .eslintrc.js to
module.exports = {
  parserOptions: {
    parser: '@typescript-eslint/parser',
    ecmaFeatures: {
      jsx: true,
    },
  },
}

src/pages/App/index.tsx will be the following

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

import HelloWorld from '@/components/HelloWorld'

import './index.css'

@Component({
  components: {
    HelloWorld,
  },
})
export default class App extends Vue {
  render () {
    return (
      <div id="app">
        <img alt="Vue logo" src={ require('@/assets/logo.png') } />
        <HelloWorld props={ { msg: 'Welcome to Your Vue.js + TypeScript App' } } />
      </div>
    )
  }
}

About src/components/HelloWorld/index.tsx, you could probably guess, but in short,

  • There needs to be a /> or a closing tag.
  • Props might not work properly. You need props={ { msg: 'Welcome to Your Vue.js + TypeScript App' } }.
  • Don't forget to add this.
  • require('@/assets/logo.png') seems to work because of some Webpack loader in Vue CLI.

TLDR / Take Home Message

  • Vetur in VSCode does not always work fully for TypeScript, especially in a Monorepo
  • The best fix is indeed, do not use TypeScript in *.vue
  • One of the workarounds is <script lang="ts" src="./index.ts">
  • Vue template string isn't as smart as TypeScript Intellisense.
  • The workaround is, do not use <template>. Use *.tsx (or *.jsx) instead.
  • It is still simple to reference foldered component if you filename is ./index.tsx
  • import HelloWorld from '@/components/HelloWorld' for example, will reference @/components/HelloWorld/index.tsx, will full IntelliSnese.
  • @angular/cli's ng generate component App doesn't even create a Single File Component, but instead create a single folder with multiple components.
./src/app/comp
├── comp.component.html
├── comp.component.scss
├── comp.component.spec.ts
└── comp.component.ts

Summary

In summary, do not use *.vue, if you want a better IntelliSense. There are other approaches in component-based structure; like a folder.

Why does Vue adopt Single File Components at all, as it isn't necessarily better than Angular's?

I have also tried https://github.com/vuejs/jsx, but Vue CLI seems to already support JSX by default.

If you stuck somewhere, see this repo. I might also add Nuxt in the future.