DEV Community

Pacharapol Withayasakpunt
Pacharapol Withayasakpunt

Posted on

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,
    },
  },
}
Enter fullscreen mode Exit fullscreen mode

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>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

GitHub logo patarapolw / vue-typescript-suggestions

An example repo for using TypeScript in Vue, with maximal VSCode suggestions

Top comments (1)

Collapse
 
michaelthiessen profile image
Michael Thiessen

I'd just like to add a couple updates to this for anyone reading this:

First, Volar has now replaced Vetur as the official Vue extension for VS Code in Vue 3.

Second, you may run into a weird error when using Volar and Typescript. Volar complains that TypeScript intellisense is disabled on template.

The solution to this is to add "jsx": "preserve" in the compilerOptions of your .tsconfig:

// .tsconfig
{
  "compilerOptions": {
    "jsx": "preserve"
  }
}
Enter fullscreen mode Exit fullscreen mode

I wrote about this solution on my blog if you happen to run into this and want more details on this error.