既存のNuxtプロジェクトにTypeScriptを導入する

現在作成しているNuxt.jsプロジェクトで途中からTypeScriptで書きたくなったので、導入方法をメモがわりに紹介します。

# Nuxt.js × TypeScript

## 新規作成の場合
vue-cliでNuxt.js×TypeScript のテンプレートをインストールできます。

```bash
vue init nuxt-community/typescript-template <my-project>
```

これだと簡単でいいですよね:astonished:
ここからが本題です！

## 既存のプロジェクトでTypeScriptを使用する

まず、`ts-loader`,`typescript`, `@types/node`をインストールします。

```bash
yarn add --dev ts-loader@3.5.0 typescript @types/node
```
~~Nuxt.jsが現在Webpack4に対応していないので、`ts-loader@3.5.0`をインストールします。
ts-loader4以上だと以下のエラーが出るので注意が必要です。~~
Nuxt.js2.0からWebpack4に対応したようです。

```bash
Module build failed: Error: You may be using an old version of webpack; please check you're using at least version 4
```
### nuxt.config.js
次にnuxt.config.jsを編集します。
moduleにtypescript.jsを記述するだけです。

```javascript:nuxt.config.js
modules: [
    "~/modules/typescript.js"
  ],
```

### typescript.js
プロジェクトrootディレクトリ直下に`modules`ディレクトリを作成し、`typescript.js`ファイルを作り、下記を記述します（typescript-templateをパクりました）

```js:typescript.js
module.exports = function() {
  // Add .ts extension for store, middleware and more
  this.nuxt.options.extensions.push("ts");
  // Extend build
  this.extendBuild(config => {
    const tsLoader = {
      loader: "ts-loader",
      options: {
        appendTsSuffixTo: [/\.vue$/]
      }
    };
    // Add TypeScript loader
    config.module.rules.push(
      Object.assign(
        {
          test: /((client|server)\.js)|(\.tsx?)$/
        },
        tsLoader
      )
    );
    // Add TypeScript loader for vue files
    for (let rule of config.module.rules) {
      if (rule.loader === "vue-loader") {
        rule.options.loaders.ts = tsLoader;
      }
    }
    // Add .ts extension in webpack resolve
    if (config.resolve.extensions.indexOf(".ts") === -1) {
      config.resolve.extensions.push(".ts");
    }
  });
};

```
### tsconfig.json
次にtsconfigを記述します。
下記の意味がきになる方は[公式のtsconfig.json](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html)を参照してください。

```json:tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "es2015"],
    "module": "es2015",
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "noImplicitAny": false,
    "noImplicitThis": false,
    "strictNullChecks": true,
    "removeComments": true,
    "suppressImplicitAnyIndexErrors": true,
    "allowSyntheticDefaultImports": true,
    "allowJs": true,
    "baseUrl": ".",
    "paths": {
      "~/*": ["./*"]
    }
  }
}
```

### index.d.ts

プロジェクトrootディレクトリ直下に`index.d.ts`という型定義ファイルを記述します

```typescript:index.d.ts
declare module "*.vue" {
  import Vue from "vue";
  const _default: Vue;
  export default _default;
}
```

これでNuxtでTypeScriptをかけるようになりました:tada::tada:

### デコレータを使う
デコレータを使う場合は`nuxt-property-decorator`をインストールします

```bash
yarn add nuxt-property-decorator
```
しかし`nuxt-property-decorator`は最近更新されていない？ようなので `vue-property-decorator`を使用してもいいかもしれないです。

### Vuexを使う
Vuexを使う場合は`vuex-class`をインストールします

```bash
yarn add vuex-class
```

## 完成
こんな感じで既存のNuxt.jsでTypeScriptを以下のように使えるようになりました:tada:

```vuejs
<template>
  <div>
    <app-hoge
      v-for="user in users"
      :key="user.id"
      :user="user"></app-hoge>
 </div>
</template>

<script lang="ts">
import { Vue, Component } from "nuxt-property-decorator";
import { State } from "vuex-class";
import AppHoge from "~/components/AppHoge.vue";

@Component({
  components: {
    AppHoge
  }
})
export default class extends Vue {
 @State users
}
</script>
```

Nuxt.jsで素晴らしいTypeScriptライフを！！！