Nuxt TypeScript + Vuex によるカウンターのサンプルコード

## 概要

- Nuxt TypeScript + Vuex を使用して「+」「-」ボタンで数値が増減するカウンターを作成する

## 今回の環境

- Node.js 13.12.0
- Nuxt.js 2.12.1
- TypeScript 3.8.3
- Nuxt TypeScript (Nuxt.js 向け TypeScript サポート)

## Nuxt TypeScript + Vuex によるカウンターのサンプルコード

### ソースコード一覧

```
├── nuxt.config.ts
├── package.json
├── pages
│   └── counter.vue
├── store
│   └── counter.ts
├── tsconfig.json
└── vue-shim.d.ts
```

### nuxt.config.ts

nuxt.config.js の TypeScript 版。

```ts
import { Configuration } from '@nuxt/types'

const config: Configuration = {
  buildModules: ['@nuxt/typescript-build']
}
export default config
```

### package.json

必要なライブラリの記述等。

```json
{
  "name": "my-app",
  "scripts": {
    "dev": "nuxt-ts",
    "build": "nuxt-ts build",
    "generate": "nuxt-ts generate",
    "start": "nuxt-ts start"
  },
  "dependencies": {
    "@nuxt/typescript-runtime": "0.4.1",
    "nuxt": "2.12.1",
    "nuxt-property-decorator": "2.5.1"
  },
  "devDependencies": {
    "@nuxt/typescript-build": "0.6.1"
  }
}
```

### pages/counter.vue

カウンター表示用のページコンポーネント。

```vue
<template>
  <div>
    <p>{{ count }}</p>
    <p>
      <button @click="increment">+</button>
      <button @click="decrement">-</button>
    </p>
  </div>
</template>

<script lang="ts">

import { Component, Vue } from 'nuxt-property-decorator'
import { CounterState } from '~/store/counter'

@Component
export default class CounterComponent extends Vue {

  get count () : number {
    console.log('Call the computed count')
    return (this.$store.state.counter as CounterState).count
  }

  // 「+」ボタンクリック時に呼ばれる
  increment () : void {
    console.log('Call the methods increment')
    // mutations の increment を呼び出す
    this.$store.commit('counter/increment')
  }

  // 「-」ボタンクリック時に呼ばれる
  decrement () : void {
    console.log('Call the methods decrement')
    // mutations の decrement を呼び出す
    this.$store.commit('counter/decrement')
  }
}
</script>
```

### store/counter.ts

カウンターの値を管理するストア。

```ts
import { MutationTree } from 'vuex'

export const state = () => ({
  count: 0
})

export type CounterState = ReturnType<typeof state>

export const mutations: MutationTree<CounterState> = {
  increment: (state) => {
    console.log('Call the mutations increment')
    state.count++
  },
  decrement: (state) => {
    console.log('Call the mutations decrement')
    state.count--
  }
}
```

### tsconfig.json

ほぼ Nuxt TypeScript の公式資料通りだが、Nuxt Property Decorator (nuxt-property-decorator) を使うため experimentalDecorators の設定を追加している。

```json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "target": "es2018",
    "module": "esnext",
    "moduleResolution": "node",
    "lib": [
      "esnext",
      "esnext.asynciterable",
      "dom"
    ],
    "esModuleInterop": true,
    "allowJs": true,
    "sourceMap": true,
    "strict": true,
    "noEmit": true,
    "baseUrl": ".",
    "paths": {
      "~/*": [
        "./*"
      ],
      "@/*": [
        "./*"
      ]
    },
    "types": [
      "@types/node",
      "@nuxt/types"
    ]
  },
  "exclude": [
    "node_modules"
  ]
}
```

### vue-shim.d.ts

Nuxt TypeScript の公式資料通り。
Vue ファイルの型を提供するための型宣言。

```ts
declare module "*.vue" {
  import Vue from 'vue'
  export default Vue
}
```

## Node.js サーバを起動

package.json に記述したライブラリをインストール。

```
$ npm install
```

Node.js サーバを起動。

```
$ npm run dev

> my-app@ dev /Users/foobar/my-app
> nuxt-ts


   ╭─────────────────────────────────────────────╮
   │                                             │
   │   Nuxt.js v2.12.1                           │
   │   Running in development mode (universal)   │
   │                                             │
   │   Listening on: http://localhost:3000/      │
   │                                             │
   ╰─────────────────────────────────────────────╯

ℹ Preparing project for development
ℹ Initial build may take a while
✔ Builder initialized
✔ Nuxt files generated
ℹ Starting type checking service...

✔ Client
  Compiled successfully in 8.15s

✔ Server
  Compiled successfully in 6.50s

ℹ Type checking in progress...
ℹ Waiting for file changes
ℹ Memory usage: 230 MB (RSS: 311 MB)
ℹ Listening on: http://localhost:3000/
```

Web ブラウザで http://localhost:3000/counter にアクセスすると「+」「-」ボタンと数値が増減するカウンターが表示される。

## 参考資料

### 環境構築

- [セットアップ \| Nuxt TypeScript](https://typescript.nuxtjs.org/ja/guide/setup.html)
- [Runtime（オプション） \| Nuxt TypeScript](https://typescript.nuxtjs.org/ja/guide/runtime.html)
- [Nuxt\.js v2\.9にTypeScriptとExpress\.jsを対応してみた \- Qiita](https://qiita.com/sauzar18/items/d68c13f200b3bc671679)
- [3分でつくる2019年版 Nuxt\.js TypeScript 開発環境設定 \- Qiita](https://qiita.com/hiropy0123/items/4ee85fdb9b19bc89056f)

### Nuxt Property Decorator (nuxt-property-decorator)

[GitHub \- nuxt\-community/nuxt\-property\-decorator: Property decorators for Nuxt \(base on vue\-property\-decorator\)](https://github.com/nuxt-community/nuxt-property-decorator)

> Handy ES / TypeScript decorators for class-style Vue components in Nuxt (based on Vue class component) and Property decorators for Vue (bases on Vue Property Decorator) and Vuex (based on Vuex Class)
> 
> This library fully depends on vue-class-component.

[Decorators · TypeScript](https://www.typescriptlang.org/docs/handbook/decorators.html)

> To enable experimental support for decorators, you must enable the experimentalDecorators compiler option either on the command line or in your tsconfig.json

### 機能実装

- [ストア \| Nuxt TypeScript](https://typescript.nuxtjs.org/ja/cookbook/store.html)
- [コンポーネント \| Nuxt TypeScript](https://typescript.nuxtjs.org/ja/cookbook/components/#script)
- [Nuxt\.js \+ Vue\.js \+ Vuex によるカウンターのサンプルコード \- Qiita](https://qiita.com/niwasawa/items/101bc39cc2949d519c13)