Convert existing Nuxt app to Typescript part 1

Nuxt-ts was announced recently and I was really excited as I was working on a nuxt app with a ASP.NET Core backend. As I have already spent a bit of time working on this, I felt it would be easier/more educational to convert the project manually rather than re-scaffold and copy contents over.

This will be an ongoing project chronicling my adventure into Nuxt with Typescript. First we will create a nuxt app and then convert it to a typescript app. This will reference the hackernews-nuxt-typescript repository as well as the Vue-cli typescript scaffolding to find a happy medium that works best with VSCode.

Before getting started, install the below dependencies: - Yarn

In this part:

  1. Scaffold a new Nuxt app
  2. Change dependencies to typescript versions
  3. Update package.json scripts to the new dependencies
  4. Port configuration to typescript
  5. Port Single File Components to Typescript

Scaffold a new Nuxt app

run npx create-nuxt-app my-typescript app

section values
serverside framework None
features linter/formatter
axios
prettier
UI framework Buefy
test Jest
package manager yarn

lets install the dependencies and run this to make sure: yarn && yarn dev

nuxt-buefy default page


Change dependencies to typescript versions

first add vue-property-decorator to the app via yarn: yarn add vue-property-decorator

open package.json and change the entry from "nuxt": "^2.X.X" to "nuxt-ts": "latest"

next, add the prettier linter to the devDependencies below:

   "tslint-config-prettier": "1.18.0"

NOTE: This will work, but some items will not lint before compile errors.


Update package.json scripts to the new dependencies

replace:

    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",

with:

    "dev": "nuxt-ts",
    "build": "nuxt-ts build",
    "start": "nuxt-ts start",
    "generate": "nuxt-ts generate",

lets run this and see the progress yarn dev

There should be a prompt to create a tsconfig.json as it is missing; press yes.

nuxt server is also being built

The serverside framework was set to None when the Nuxt app was created… but there is a server being built.

looking at the page we will find missing css and errors saying:

[Vue warn]: Unknown custom element: <b-icon> - did you register the component correctly? For recursive components, make sure to provide the "name" option.

default page after changing to ts

The server being built is a hint; nuxt.config.js is not being loaded and a default is executed in place. Because the default doesn’t use Buefy, the b-icon is also not resolved and a warning is thrown. This is fixed in the next step.


Port configuration to typescript

Change the name of nuxt.config.js to nuxt.config.ts

Then change the module.exports = to export default

The default page should be showing with Buefy again.

nuxt-buefy default page


Port Single File Components to Typescript

NOTE: This section has a variety of pitfalls, so lets go through the common ones as the show up.

First convert layouts/default.vue to the vue-property-decorator:

  1. change the script language to ts and add the component decorators
...
<script>
export default {
...
...
<script lang="ts">
import {Vue, Component} from 'vue-property-decorator'

@Component
export default App extends Vue {
...

There should be an error similar to the one below: tsConfig error

This is caused by property decorators being an experimental typescript feature. Enable them by adding the below to tsconfig.json compilerOptions:

  "compilerOptions": {
    "baseUrl": ".",
    "types": [
      "@types/node",
      "@nuxt/vue-app"
    ],
    "experimentalDecorators": true, // add this
  }

NOTE: this may require a restart for VSCode to understand the tsconfig changes

Next, do the same for pages/index.vue

in the script section change:

<script>
import Card from '~/components/Card'

export default {
  name: 'HomePage',

  components: {
    Card
  }
}

to:

<script lang="ts">
import { Vue, Component } from 'vue-property-decorator';
import Card from '~/components/Card'

@Component({
  components: {
    Card
  }
})
export default class HomePage extends Vue {}

There should be another error here:

cannot import .vue files

This one is trickier and has some history(spoilers it’s really long). Typescript, by default, will only look for files with extension .ts and there seems to be two methods of fixing this. One is to modify the webpack config and the other is to extend the typing definitions with a shim as it is easier than extending webpack (personal opinion only, don’t @me).

Add a shims.d.ts

declare module '*.vue' {
  import Vue from 'vue';
  export default Vue;
}

NOTE: A VSCode restart may be required to pickup the changes

Next change components/Card.vue from:

<script>
export default {
  props: {
    title: {
      type: String,
      required: true
    },
    icon: {
      type: String,
      required: true
    }
  }
}

to:

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

@Component
export default class Card extends Vue {
    @Prop({
      required: true
    })
    title!: string;

    @Prop({
      required: true
    })
    icon!: string;
}

Some brief tips:

  • The @Prop decorator takes on all the definitions property definitions that typescript is not built for (namely if the property is required and the default value).
  • The ! after the property name is to declare that the property can be unintialized (the @Prop makes it reactive) because it is set during the vue lifecycle.

Extras: tweaking the linter/formatter

For the most part, the prettier formatter works well. Coming from a C# background however, I would like a couple of changes. namely semicolons at the end of statements. Official docs says that adding "semi": true" to .prettierrc should work.

Next, increase the max line length by setting "printWidth": 120 in the .prettierrc file.

Lastly, add commas to everything! "trailingComma": "all"

This will conclude part 1. Any corrections can be sent via Twitter DM