Power a Nuxt application with TypeScript

I updated the Nuxt.js setup part in a new which add Vuetify and Vue-i18n as well as Storybook as a bonus:

April-2020 update:

From Nuxt 2.9 and on-ward, please use the official TypeScript support of Nuxt:

I have updated the repository which makes some part of this article obsolete.

Also, TSLint has been deprecated in favour of ESLint.

NuxtJS & TypeScript logos

Nuxt recently (January 2019) released the pushing TypeScript integration one step forward. First of all, kudos to Nuxt team!

Nuxt-ts demo from Nuxt 2.4.0. release note

I gave a try to nuxt-ts from a project from scratch. Guillaume Dormoy already made a .

I aim at going a bit further with Vuex, Jest and stuff to check how a full NuxtTS application would be.

Readers who prefer to read on Github, .

Updates:

  • 16-Feb-2019: initialisation
  • 18-Feb-2019 : update to meet Nuxt standards (logic moved at components level and each component is tested)
  • 25-Feb-2019: Adding “Reuse mapped Vuex elements” section
  • 03-Mar-2019: Switch from vue-property-decorator to nuxt-property-decorator and correcting Vuex state definition

Project setup

Initialise a nuxt with minimal configuration with yarn as package manager. I chose the minimal configuration (no plugin, no style library, etc) so that I can see in package.json what need to be added to be TypeScript compliant.

yarn create nuxt-app {your project name}

More information on .

Typescript

I mainly rely on the two following links for a “painless” TypeScript integration

Add Typescript to the project

Add nuxt-ts and nuxt-property-decorator

yarn add nuxt-tsyarn add --dev nuxt-property-decorator

Change nuxt to nuxt-ts in package.json scripts:

package.json

Create and configure tsconfig.json:

tsconfig.json

Note to VS Code users: VS Code rock with aliases. To have it work, ensure that baseUrl, paths and if required include / exclude are properly defined. More about it on by Claudio Cicali.

Update existing code

Nuxt CLI has created a Logo component and an Index page. I won’t dive in details in .

Update pages/index.vue :

vuepages/index.vue

The component-wrapper is not relevant to this tutorial and only serves aesthetic purpose. Please check .

yarn dev should run without any issue.

To ensure that TypeScript classes works properly, I have created a lib/ folder with a dummy.ts file:

lib/dummy.ts

To use those classes, create a TypescriptClass component:

components/TypescriptClass.vue

TypescriptClass component can then be added in our home page :

pages/index.vue

Now our code is TypeScript ready! 👌

Adding Prettier & TSLint

TypeScript is cool but is even cooler with , an opinionated formatter, and , a TypeScript linter.

yarn add --dev prettier tslint tslint-config-prettier

Prettier configuration

Add prettier configuration via a .prettierrc file. Options can be found on:

.prettierrc

TSLint configuration

Add TSLint configuration via a tslint.json file:

tslint.json

Note: I personally do not want to prefix my interface with a capitalised “I” hence the interface-name rule.

Code update

TSLint now complains about my way of writing code. To please it, I had to:

  • Add scope on properties and methods
  • Split dummy.ts into and as TypeScript recommends one class per file.
  • Organize import by alphabetical orders. I split my import between third-party imports and this project specific imports.
  • Use TypeScript types ( number instead of Number, string instead of String, etc)
  • Add / update types in JSDocs as well

Testing

Time to test our code with .

Adding Jest

yarn add --dev jest vue-jest @vue/test-utils ts-jest @types/jest

Update tsconfig.json:

tsconfig.json

Add a "test": "jest" script in package.json. Feel free to add the --verbose and/or --coverage options

Testing plain TypeScript

Let’s create a tests/ folder and write our first tests:

Nothing fancy, just some basic TypeScript testing. At this stage, yarn test should fail because Jest is not told yet how to handle TypeScript. To fix that, create a jest.config.js :

jest.config.js

Testing Vue components

Time to jump into Vue testing. Let’s try to test the Logo components. In tests/components/Logo.spec.ts:

tests/components/Logo.spec.ts

VSCode is not happy about import Logo from @/components/logo.vue claiming that Cannot find module '@/components/logo.vue'. Declare Vue types by adding a ts-shim.d.ts :

ts-shim.d.ts

This solution was found thanks to .

If VS Code keeps complaining about .vue files, add in your tsconfig.json:

tsconfig.json

Now Vue components can be tested. How about pages? More globally, how about components involving other components? Let’s try with tests/pages/index.spec.ts:

tests/pages/index.spec.ts

Jest will complain:

console.error node_modules/vue/dist/vue.runtime.common.dev.js:621[Vue warn]: Unknown custom element: <logo> - did you register the component correctly? For recursive components, make sure to provide the "name" option.  found in  ---> <Index>         <Root>

Okay, Logo is not declared. Let’s declare it in components/Logo.vue:

components/Logo.vue

Vuex

Our app would feel lonely without a store. Let’s add Vuex. I am pretty new with TypeScript in Vuex so I am discovering in real time 😉. guided me.

Store definition

To simulate a real life application, let’s use Vuex modules. .

I created a counter module with split files:

- store
- counter
- actions.ts
- const.ts
- getters.ts
- mutations.ts
- state.ts
- types.ts
- types.ts

Apart from Nuxt naming convention, files are defined as:

  • store/counter/const.ts: some convenience constants for vuex-class later usage
  • store/counter/type.ts: counter module state types
  • store/type.ts: root module state types

For more details regarding Vuex in Nuxt, please check .

counter store

Kudos to Francesco Vitullo for .

Store usage

New logic calls for a new component. Create a Counter component:

components/counter.vue

Counter can be added to our home page:

pages/index.vue

Testing Vuex based components

To test our Counter component, we need to initialise the Vuex store.

As we are using TypeScript, our mock has to be properly typed:

tests/components/counter.vue

Reuse mapped Vuex elements

nuxt-property-decorator includes . (from which is very convenient to map Vuex state in a TypeScript compliant way.

An alternative I have not tried is (from )

components/Counter.vue

Notice that even if we wrapped our incrementaction, all tests should pass.

The End

And tadaa!! 🎉 🎉

All these files and this tutorial can be found on .

Many thanks for reading so far! Feel free to clap if you enjoy this tutorial. And please share your thoughts in comments!

🇫🇷 | Vue.js Front-end dev @Tokyo 🇯🇵 | Writing about web dev & related | Focusing on optimisation, all for laziness |