toshi-toma blog

主にフロントエンド、作業ログあとは色々なメモ ✍️ 🍅

React+ReduxのプロジェクトにTypeScriptを導入する その1(準備・設定)

はじめに

趣味で開発しているReact+ReduxのプロジェクトにTypeScriptを導入したので、その内容をまとめておきます。

Reduxを使っていない、ReactだけのプロジェクトにTypeScriptを導入する流れは以前Qiitaの記事でまとめました。 qiita.com

React+ReduxのプロジェクトにTypeScriptを導入する作業としてやったことは以下の通り

  1. Babel+webpackでTypeScriptのコンパイルを行えるように設定を変更
  2. tsconfig.jsonコンパイルの設定を記述
  3. ESLintでTypeScriptをチェックできるように@typescript-eslint/eslint-pluginのインストールと設定
  4. Reactのファイルは.tsx、それ以外のJSファイルは.tsに拡張子を変更
  5. プロジェクト内で必要な型定義ファイルをインストール
  6. コンパイルエラーに対応/修正
  7. prop-typesを削除

TypeScriptを用いたReactのファイルは拡張子が.tsx、それ以外のJavaScriptファイルは.tsになります。 なので今回は「Babelとwebpackの設定をTypeScript用に適切に変更した状態で、Reactのファイルが全て.tsx、それ以外のファイルは.tsになりコンパイルが通る」ことがゴールです。

ここから、各作業の内容について記載します。

なお、この記事ではTypeScriptを導入するにあたり、行う設定などの準備段階(作業1~3)のみ紹介します。
なので、この記事ではReduxに関する内容は登場せず、ReactのプロジェクトにTypeScriptを導入する際の設定内容とほぼ同様です。

実際にTypeScriptで型を導入する(手順4~7)については、後日に別記事で紹介しようと思います。

Babel+webpackでTypeScriptのコンパイルを行えるように設定を変更

まずは、Babel+webpackのビルドプロセスでTypeScriptのコンパイルを行えるようにします。

TypeScriptをwebpackで処理する場合、ts-loaderを使う方法とBabel(@babel/preset-typescript)を使う方法があるようです。 Babelは、設定でTarget Browserを指定してPolyfillが使えたり、pluginを使って新しいプロポーザルの機能を使えること、またLinterやテストランナー、ビルドシステムなどはBabelをサポートしているので別途考慮する必要(ts-jest, ts-node, ts-karma etc)がなくなる。など、結局Babelを使うことになりそうで、使った場合の方がメリットが多そうに思ったので今回はts-loaderではなく、Babel(@babel/preset-typescript)を使うことにしました。

ts-loaderとpreset-typescriptの比較はこの記事が分かりやすかったです。

iamturns.com

必要なライブラリをインストールします。

$ npm i -D typescript @babel/preset-typescript

webpackの設定

webpack.config.jsを以下のように変更しました。 今回、エントリーファイルはindex.tsxとしました。

...
module.exports = {
-  entry: path.resolve(__dirname, 'src/index.js'),
+  entry: path.resolve(__dirname, 'src/index.tsx'),

    output: {
      path: path.resolve(__dirname, 'public'),
      module: {
         rules: [
            {
-              test: /\.(js|jsx)$/,
+              test: /\.tsx?$/,
               exclude: /node_modules/,
               loader: 'babel-loader'
      }
  },

  resolve: {
-    extensions: ['.js', '.jsx']
+    extensions: ['.ts', '.tsx', '.js']
  },
  ...

Babelの設定

babel.config.jsを以下のように変更しました。

  presets: [
     ...
+   '@babel/preset-typescript',
    '@babel/preset-react'
  ],
  ...

tsconfig.jsonコンパイルの設定を記述

TypeScriptのコンパイルに関する設定はtsconfig.jsonに記載します。 以下のコマンドでtsconfig.jsonの雛形を作成できます。

$ ./node_modules/.bin/tsc --init

作成されたファイルを編集して、必要な設定を行いました。

※ compilerOptionsの各設定は、まだちゃんと確認できていないので、不要な設定も入っていると思います。

{
  "compilerOptions": {
    /* Basic Options */
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
    "module": "ESNext",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    "lib": [
      "dom",
      "es2018"
    ],                        /* Specify library files to be included in the compilation. */
    "jsx": "react",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
    "outDir": "./dist/",                        /* Redirect output structure to the directory. */

    /* Strict Type-Checking Options */
    "strict": true,                           /* Enable all strict type-checking options. */

    /* Additional Checks */
    "noUnusedLocals": true,                /* Report errors on unused locals. */
    "noUnusedParameters": true,            /* Report errors on unused parameters. */
    "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */

    /* Module Resolution Options */
    "moduleResolution": "node",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. */
    "typeRoots": ["node_modules/@types"],                       /* List of folders to include type definitions from. */
    "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
    "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
  },
  "include": ["src"],
  "exclude": ["node_modules"]
}

これでコンパイルの設定が行えました。

ESLintでTypeScriptをチェックできるように@typescript-eslint/eslint-pluginのインストールと設定

TypeScript用にLintの設定も行いました。

これまでTypeScriptのLinterはTSLintがメジャーでしたが、今は@typescript-eslint/eslint-pluginにより ESLintでのチェックも行えるようになっているので、TSLintではなくESLintにTypeScriptの設定を追加する形で行いました。

参考にした記事はこちらの記事です。

teppeis.hatenablog.com

※ 作業の途中でESLintの実行時にエラーが発生したが、ESLint周りのライブラリバージョン(ESLint, eslint-config-airbnb)が古かったのが問題っぽく、ライブラリを上げると直りました。

@typescript-eslint/eslint-pluginをインストール

$ npm i -D @typescript-eslint/eslint-plugin

.eslintrc.jsを以下のように変更しました。

...
-  parser: 'babel-eslint',
  parser: "@typescript-eslint/parser",
  parserOptions: {
    "sourceType": "module",
    "project": "./tsconfig.json",
    "ecmaFeatures": {
      "jsx": true
    }
  },

...
  extends: [
    ...
    "plugin:@typescript-eslint/recommended",
    ...
    "prettier/@typescript-eslint",
  ],
  plugins: [
    ...
    "@typescript-eslint",
    ...
  ],
  rules: {
    ...  
     // TypeScript
    "@typescript-eslint/no-unused-vars": "error",
    "@typescript-eslint/explicit-member-accessibility": "off",
    "@typescript-eslint/no-object-literal-type-assertion": "off",
    "@typescript-eslint/prefer-interface": "off",
    "@typescript-eslint/camelcase": "off",
    "@typescript-eslint/explicit-function-return-type": "off",
  },
  "settings": {
    "import/resolver": {
      "node": {
        "extensions": [".js", ".jsx", ".ts", ".tsx"]
      }
    }
  }
...

とりあえずルールとして@typescript-eslint/recommendedを設定していますが、TSLint互換の結構厳しいルールが多く入っているので、個別に必要なルールだけ追加した方がいいかもしれません。

また、VSCodeでもTypeScriptのファイルをESLintでチェックしたかったのでVSCodeのsettings.jsonにも設定を追加しました。

  "eslint.validate": [
    "javascript",
    "javascriptreact",
    "typescript",
    "typescriptreact"
  ],
  "eslint.autoFixOnSave": true,

※ たまにTypeScriptのファイルのautoFixがVSCode上で動作しない事態が発生してるのですが、理由はまだ調べれてないです。

まとめ

この記事では、React+ReduxのプロジェクトにTypeScriptを導入するにあたり
準備段階として、webpack、Babel、TypeScript、ESLintの設定を行いました。

これでTypeScriptでコードを書く準備は整ったので、次の記事では実際にその流れを紹介していこうと思います。