Nuxt.js + TypeScript + Vuex で簡単な Todo リストを作るチュートリアル
はじめに
Nuxt.js + TypeScript + Vuex(ストア)で簡単な Todo リスト制作を行った際の覚書です。
完成品はこちら → https://github.com/tigrig29/todo-nuxt-typescript
2019/09/20 執筆
- Nuxt
- v2.10.0 ~ v2.14.0 あたりが対象です(v2.15.0 は未確認です)
Nuxt TypeScript 公式 も参照して、比較しながら読んで頂けると幸いです。
対象
- Nuxt.js 経験あり
- TypeScript 試したい
- Vuex(ストア)も使ってちゃんと型推論(入力補完)させたい
筆者の環境
- Windows10
- VSCode
- yarn
Nuxt + TypeScript の環境構築
当記事では触れません。
環境構築が必要な方は、以下の記事を参考にしてみてください。
Nuxt + TypeScirpt 環境構築 for Windows, VSCode(2019/09/20)
また、Nuxt + TypeScript + Vuex の基本的な構築方法だけを知りたい方は、Nuxt + TypeScript で Vuex を扱うために ~ vuex-module-decorators を御覧ください。
ディレクトリ構成
今回、Nuxt + TypeScript の環境構築に加えて、作成するフォルダ、ファイルは以下のとおりです。
@
├── assets
├── components
├── layouts
├── middleware
+ ├── models
+ │ ├── HTMLElementEvent.ts ← クリックイベント等の e.target を型推論できるようにする型定義ファイル
+ │ └── Todo.ts ← Todo の型定義ファイル
├── pages
+ │ └── index.vue ← 編集: 簡単な Todo リストページ の vue ファイル
├── plugins
├── static
├── store
+ │ ├── index.ts ← Store をインポートするための定義を記述するファイル1
+ │ └── todos.ts ← Todo リストのストア
+ └── utils
+ └── store-accessor.ts ← Store をインポートするための定義を記述するファイル2
vuex-module-decorators のインストール
Nuxt + TypeScript + Vuex で型推論を行えるようにするため、vuex-module-decorators
をインストールします。
yarn add -D vuex-module-decorators
npm install --save-dev vuex-module-decorators
Todo を管理する Store の作成
~/models/Todo.ts
の作成
あらかじめ Todo の型定義を作成しておきます。
export interface Todo {
id: number
text: string
done: boolean
}
~/store/todos.ts
の作成
続いて、Todo リストの Store を作成します。
基本的には Nuxt で Store を作成するとき(モジュールモード)と同様ですが、今回は JavaScript ではなく TypeScript で記述します。
具体的なコードの内容は、コード内のコメントを参照してください。
import { Module, VuexModule, Mutation } from 'vuex-module-decorators'
import { Todo } from '~/models/Todo'
// stateFactory: true → Vuex をモジュールモードで扱うために指定
@Module({ stateFactory: true, namespaced: true, name: 'todos' })
export default class Todos extends VuexModule {
todos: Todo[] = []
/**
* Todo を追加する
* @param text Todo テキスト
*/
@Mutation
add(text: string) {
const todos: Todo[] = this.todos
// Todo を作成
const todo: Todo = {
// リストがない場合、id = 0
// リストがある場合、id = リストの最終要素の id + 1
id: todos.length === 0 ? 0 : todos[todos.length - 1].id + 1,
text,
done: false
}
// リストに Todo を追加
this.todos.push(todo)
}
/**
* Todo を削除する
* @param todo 削除する Todo インスタンス
*/
@Mutation
remove(todo: Todo) {
this.todos.splice(this.todos.indexOf(todo), 1)
}
/**
* Todo の done(完了状態)を切り替える
* @param todo 完了状態を切り替える対象の Todo インスタンス
*/
@Mutation
toggle(todo: Todo) {
todo.done = !todo.done
}
}
Store をインポートするためのファイル作成
~/utils/store-accessor.ts
の作成
作成した Store(Todo リスト)をインポートするための store-accessor.ts
を作成します。
import { Store } from 'vuex'
import { getModule } from 'vuex-module-decorators'
import Todos from '~/store/todos'
// eslint-disable-next-line import/no-mutable-exports
let todosStore: Todos
/**
* ストアを初期化する(型推論できるモジュールとして取得する)
* @param store Vuex.Store
*/
function initializeStores(store: Store<any>): void {
// Todos を型推論できるストアモジュール化
todosStore = getModule(Todos, store)
}
export { initializeStores, todosStore }
コード中間の // eslint-disable-next-line import/no-mutable-exports
は、ESLint の設定によっては不要です。
※ vuex-module-decorators - npm ので説明されているコードをそのまま使っていますが、TypeScript エラーとなります。仕方ないので、ESLint を無効化しています。
~/store/index.ts
の作成
store
ディレクトリ直下に index.ts
ファイルを作成します。
これは ~/utils/store-accessor.ts
と連携して、 Component 等の vue ファイルから Store にアクセスできるようにするファイル です。
import { Store } from 'vuex'
import { initialiseStores } from '~/utils/store-accessor'
const initializer = (store: Store<any>) => initialiseStores(store)
export const plugins = [initializer]
export * from '~/utils/store-accessor'
~/pages/index.vue
の編集: Todo リストの実装
~/pages/index.vue
を編集して、Todos ストアを用いた Todo リストページを作成します。
※ 当記事では TypeScript の実装を OptionsAPI で行っていますが、ClassAPI、CompositionAPI お好みの方法で実装してみてください。
参考:Nuxt TypeScript での API 採用方法について
<template>
<div id="app">
<h1>簡単な Todo リスト</h1>
<!-- Todo リスト -->
<ul>
<li v-for="(todo, i) in todos" :key="i">
<input type="checkbox" :checked="todo.done" @change="toggle(todo)" />
<span :class="{ done: todo.done }">{{ todo.text }}</span>
<button @click="remove(todo)">削除</button>
</li>
<!-- 新規 Todo 入力エリア -->
<li>
<input placeholder="Todo を入力" @keyup.enter="addTodo" />
</li>
</ul>
</div>
</template>
<script lang="ts">
// 下記、「OptionsAPI で記述」するために必要
import Vue from 'vue'
// Todo の型定義をインポート
import { Todo } from '~/models/Todo'
// Todo リストのストアモジュールをインポート
import { todosStore } from '~/store'
// OptionsAPI で記述
export default Vue.extend({
computed: {
todos(): Array<Todo> {
// リスト(todos)を取得
// ※ todosStore. と打つと、インテリセンス(入力補完機能)が働く
return todosStore.todos
}
},
methods: {
// Todo の追加
addTodo(e): void {
todosStore.add(e.target.value)
e.target.value = ''
},
// Todo の削除
remove(todo: Todo) {
todosStore.remove(todo)
},
// Todo の done(完了状態)切り替え
toggle(todo: Todo) {
todosStore.toggle(todo)
}
}
})
</script>
<style>
/* 完了状態の Todo には打消し線をつける */
.done {
text-decoration: line-through;
}
</style>
import { todosStore } from '~/store'
と記述するだけで、ストアモジュールが使えるようになります。
todosStore.
と、ドットまで入力すればインテリセンス(入力補完機能)が働き、自分が定義した State や Mutations, Actions ……全てが確認できるので、とても作業効率が上がりますね!
また、JavaScript では this.$store.state.todos.todos
と書かなければならないところが、TypeScript では todosStore.todos
だけで済むことや、同じ記述方法で Mutations や Actions も呼び出せるところが良いですね。
最後に動作確認
- ソースコードは Github にて公開しています
- サンプルアプリは Netlify に公開中(実際に使ってみたい方は ↓ の URL へお越しください)
参考記事
Nuxt + TypeScript + Vuex
- 【Nuxt.js】Todo リストで理解する TypeScript で Vuex 入門
- Examples of how to use the modules in a Vue component
- Nuxt.js + Typescript + Vuex する現時点のベストと思う方法
- vuex + typescript を vuex-module-decorators で無敵になる
Nuxt + TypeScript
- Nuxt + TypeScirpt 環境構築 for Windows, VSCode(2019/09/20)
- https://teratail.com/questions/211457
- Components - Nuxt TypeScript