Power a Nuxt application with TypeScript

Al-un
Al-un
Feb 17, 2019 · 5 min read

July-2020 update:

I updated the Nuxt.js setup part in a new article which add Vuetify and Vue-i18n as well as Storybook as a bonus: https://medium.com/@Al_un/nuxt-js-setup-storybook-powered-f023b4ef351d

April-2020 update:

From Nuxt 2.9 and on-ward, please use the official TypeScript support of Nuxt: https://typescript.nuxtjs.org/guide/setup.html

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

Also, TSLint has been deprecated in favour of ESLint.


Image for post
Image for post
NuxtJS & TypeScript logos

Nuxt recently (January 2019) released the 2.4.0 version 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 good introduction.

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, this way please.

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 Nuxt getting started page.

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 this article by Claudio Cicali.

Update existing code

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

Update pages/index.vue :

vuepages/index.vue

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

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 Prettier, an opinionated formatter, and TSLint, a TypeScript linter.

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

Prettier configuration

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

.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 another_class.ts and some_class.ts 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 Jest.

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 Beetaa comment on this Github issue.

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 😉. This article guided me.

Store definition

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

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 Nuxt documentation.

counter store

Kudos to Francesco Vitullo for his article to teach me about Vuex types.

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 vuex-class. (from this Vuex and Typescript article) which is very convenient to map Vuex state in a TypeScript compliant way.

An alternative I have not tried is vuex-typex (from this Writing Vuex stores in TypeScript article)

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 this repository.

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

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store