環境づくりの勉強がてら ReactHooks・テストは JEST + Enzyme で作っていたプロジェクトを TypeScript 化したメモ
1. TypeScript 化のパッケージをインストール して babel 関連のパッケージをアンインストール
TypeScript 化するにあたって必要なパッケージをインストールする
$ yarn add -D typescript @typescript-eslint/eslint-plugin @typescript-eslint/parser
React まわりの types をインストール
$ yarn add -D @types/react @types/react-dom @types/node
tsc
でコンパイルするので babel は不要になる
$ yarn remove @babel/core @babel/preset-env @babel/preset-react
.babel.comfig.js
も削除
2. 設定ファイルの作成
tsconfig.json
下記コマンドで設定ファイルを生成
$ tsc --init
tsconfig.json
ができるので編集
{ "compilerOptions": { "lib": ["dom", "ES2017"], "allowJs": true, "jsx": "react", "declaration": true, "noUnusedLocals": true, "noUnusedParameters": true, "noUnusedParameters": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "moduleResolution": "node", "esModuleInterop": true, "experimentalDecorators": true, "emitDecoratorMetadata": true, }, "include": ["src/**/*"], "exclude": ["node_modules", "tests"] }
段階的に TypeScript 化しようと思ったので、"allowJs": true,
を設定しました。
.eslintrc.json
babel の設定で作成していた .eslintrc.json
を編集します
{ + "parser": "@typescript-eslint/parser", "extends": [ - "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "prettier/@typescript-eslint", "plugin:prettier/recommended", "plugin:react/recommended" ], - "env": { - "browser": true, - "node": true - }, "parserOptions": { "ecmaVersion": 2018, "sourceType": "module", - "ecmaFeatures": { - "jsx": true - } }, "plugins": ["react-hooks"], "rules": { + "no-console": ["warn", { "allow": ["warn", "error"] }], "react-hooks/rules-of-hooks": "error", "react-hooks/exhaustive-deps": "error", - "space-before-function-paren": ["error", "never"], + "space-before-function-paren": 0, + "@typescript-eslint/indent": 0, + "@typescript-eslint/no-explicit-any": 0, "semi": ["error", "always"], "object-shorthand": ["error", "always", { "avoidQuotes": true }] } }
function method<T extends (…arg: any) => any>() {…}
という書き方でどうやっても Unexpected space before function parentheses
になってしまったの space-before-function-paren
のルールは無効にしました。
3. build コマンドの作成
cjs, esm 両パターンでコンパイルします。
package.json
に build コマンドとそれぞれのエントリーポイントの指定作成します
package.json
{ "main": "dist-cjs/index.js", "module": "dist-esm/index.js", "types": "dist-cjs/index.d.ts", … "scripts": { "build:cjs": "tsc --project . --module commonjs --outDir ./dist-cjs", "build:esm": "tsc --project . --module esNext --outDir ./dist-esm", … }, }
build されたファイルは git 管理したくないので .gitignore
に出力されるディレクトリを追加します
.gitignore
/dist-cjs /dist-esm
一度にコンパイルできるようにする
yarn build
コマンドで一度に両方 build したいので複数の npm script を実行できる npm-run-all
を使って実現します
npm-run-al
をインストール
$ yarn add -D npm-run-all
package.json
にコマンドを追加
{ "scripts": { "build": "npm-run-all -s build:cjs build:esm", … } }
ここまでで、React のファイルを TypeScript で扱うことができるようになりました。
4. Test も TypeScript 化する
続いて JEST + Enzyme で行っていたテストも TypeScript 対応にしていきます。
必要なパッケージのインストール
$ yarn add -D ts-jest @types/jest @types/enzyme @types/enzyme-adapter-react-16
Jest用のTypeScriptプリプロセッサ(
ts-jest
)をインストールします。これにより、Jestはその場でTypeScriptをトランスパイルすることができ、source-mapをサポートします
cf. Jest - TypeScript Deep Dive 日本語版
Jest の設定 ( jest.config.js
)
テストを ts-jest
で変換するように設定し、対象ファイルに .ts
, .tsx
を含めるように変更します。
jest.config.js
module.exports = { // An array of file extensions your modules use moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx', 'node'], // A map from regular expressions to paths to transformers transform: { "^.+.(js|jsx|ts|tsx)$": "ts-jest" }, // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation transformIgnorePatterns: [ "/node_modules/.+.(js|jsx)$", ], }
enzyme の設定ファイルを typescript に変更する
enzyme-adapter-react-16
の Adapter
を設定していたファイルの拡張子を .js
から .ts
に変更
- __tests__/setup.enzyme.js +__tests__/setup.enzyme.ts
テスト実行時に自動的に読み込むファイルを .ts
のものに変更します。
jest.config.js
module.exports = { // A list of paths to modules that run some code to configure or set up the testing framework before each test - setupFilesAfterEnv: ['<rootDir>/__tests__/setup.enzyme.js'], + setupFilesAfterEnv: ['<rootDir>/__tests__/setup.enzyme.ts'], }
これで、テストも TypeScript で動作するように出来ました!
作業したログを元にしたメモなので参考程度に…
ちゃんと理解するにはそれぞれの設定とかのドキュメントをしっかり読む必要がありそうです。(英語力…)
[参考]
- Basic Types · TypeScript
- ESLint - Pluggable JavaScript linter
- Jest - TypeScript Deep Dive 日本語版
- 2019年版: 脱Babel!フロント/JS開発をTypeScriptに移行するための環境整備マニュアル - Qiita
- React+CSSModulesな環境で、ちょびっとだけTS化した話 - Qiita
- TypeScriptを徐々に導入する - Qiita
- TypeScriptでジェネリクス(Generics)を理解するための簡単なチュートリアル | I am mitsuruog
- typescript - Type 'null' is not assignable to type 'T' - Stack Overflow
- reactjs - What typescript type do I use with useRef() hook when setting current manually? - Stack Overflow
- npm-run-all - npm