新規に作ろうとして環境作るまでに盛大にハマったのでメモ
環境
"typescript": "^4.3.5" "eslint": "^7.30.0", "prettier": "^2.3.2", "jest": "^27.0.6",
最終的にできたもの
TL:DR;
TypeScript + ESLint+ Prettier の環境を作る
TypeScript
$ npm i --save-dev typescript $ npx tsc --init
tsconfig.json
{ "compilerOptions": { "target": "es5" , "module": "commonjs, "lib": [ "dom", "ES2017"], // `.d.ts` ファイルを生成 "declaration": true, // sourcemap の `.d.ts` ファイルを生成 "declarationMap": true, "sourceMap": true, "strict": true, // 使われているthisの型が暗黙的にanyになる場合にエラー "noImplicitThis": true, // 宣言されたが使用されていない変数が存在する場合にエラー "noUnusedLocals": true, // 条件分岐の条件によって明示的なreturnがされないルートがあるとエラー "noImplicitReturns": true, "esModuleInterop": true, // Enables experimental support for ES7 decorators. "experimentalDecorators": true, // Enables experimental support for emitting type metadata for decorators. "emitDecoratorMetadata": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, "include": ["src/**/*", "tests/**/*"], "exclude": ["node_modules"] }
Build の設定
Build 自体は npx tsc --project .
で実行できる
commonJS, esNext それぞれでビルドできるように npm script を追加する
package.json
"scripts": { + "build:cjs": "tsc --project . --module commonjs --outDir ./dist-cjs", + "build:esm": "tsc --project . --module esNext --outDir ./dist-esm", + "build": "npm run build:cjs && npm run build:esm" }
ESLint + Prettier
ESLint + Prettier を実行する npm script を追加
package.json
{ "scripts": { "build:cjs": "tsc --project . --module commonjs --outDir ./dist-cjs", "build:esm": "tsc --project . --module esNext --outDir ./dist-esm", "build": "npm run build:cjs && npm run build:esm", + "lint": "eslint \"src/**/*.{js,ts}\"", + "lint:fix": "eslint --fix \"src/**/*.{js,ts}\"", + "format": "prettier --write \"src/**/*.{js,ts}\"" } }
必要なパッケージのインストール
$ npm i --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin $ npm i --save-dev prettier eslint-config-prettier $ touch .prettierrc $ npx eslint --init
.eslintrc.js
module.exports = { env: { browser: true, es2021: true, node: true, }, extends: [ 'airbnb-base', // 型を必要としないプラグインの推奨ルールをすべて有効 'plugin:@typescript-eslint/recommended', // 型を必要とするプラグインの推奨ルールをすべて有効 'plugin:@typescript-eslint/recommended-requiring-type-checking', 'prettier', // ESLint で Prettier の規則もエラーとして検出する設定 'prettier/@typescript-eslint', ], plugins: ['@typescript-eslint'], parser: '@typescript-eslint/parser', parserOptions: { ecmaVersion: 12, sourceType: 'module', }, rules: { 'newline-before-return': 'error', 'no-console': 'warn', 'no-var': 'error', }, };
.prettierrc
{ "printWidth": 120, "tabWidth": 2, "semi": true, "singleQuote": true, "trailingComma": "es5", "arrowParens": "always", "useTabs": false, "endOfLine": "lf" }
VS Code で保存時に ESLint + Prettier でフォーマットする設定
$ mkdir .vscode $ touch .vscode/settings.json
.vscode/settings.json
{ editor.tabSize": 2, "eslint.validate": [ "javascript", "typescript", ], // ファイル保存時の自動フォーマット有効 "editor.formatOnSave": true, // デフォルトフォーマッターをPrettierに指定 "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.codeActionsOnSave": { // ファイル保存時に ESLint でフォーマット "source.fixAll.eslint": true }, "[markdown]": { "files.trimTrailingWhitespace": false } }
TypeScript + ESLint の設定エラー
Error while loading rule '@typescript-eslint/await-thenable': You have used a rule which requires parserServices to be generated. You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.
ESLint の parserOptions.project
に明示的に tsconfig
ファイルを指定する必要がある
.eslintrc.js
plugins: ['@typescript-eslint'], parser: '@typescript-eslint/parser', parserOptions: { - ecmaVersion: 12, - sourceType: 'module', + project: './tsconfig.json', },
cf.
- Release v2.0.0 · typescript-eslint/typescript-eslint · GitHub
- typescript-eslint v2.x.xでパースに失敗する場合の対処法 - Qiita
.eslintrc.js
編集中に VS Code が延々エラーを表示してくる
Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser. The file does not match your project config: .eslintrc.js. The file must be included in at least one of the projects provided.
.eslintrc.js
も監視対象になっていてプロジェクトに使われてないという警告。
.eslintrc.js
は設定ファイルでプロジェクトに使わないので対象外にする。
$ touch .eslintignore
.eslintignore
/.eslintrc.js
Prettier + ESLint の設定エラー Error: "prettier/@typescript-eslint" has been merged into "prettier" in eslint-config-prettier 8.0.0.
Version 8.0.0 (2021-02-21)
から ESLint の extends
に書く prettier/@typescript-eslint
の指定は prettier
のみで OK になった
.eslintrc.js
extends: [
'airbnb-base',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'prettier',
- 'prettier/@typescript-eslint',
],
cf. eslint-config-prettier/CHANGELOG.md at main · prettier/eslint-config-prettier · GitHub
ESLint のルール設定
airbnb-base
を入れたので発生している可能性あり
named export がエラーになる Prefer default export import/prefer-default-export
export const MyModule = () => {}; // => ESLint: Prefer default export import/prefer-default-export
import/prefer-default-export
オプションを OFF にする
.eslintrc.js
rules: {
+ 'import/prefer-default-export': 'off',
'newline-before-return': 'error',
'no-console': 'warn',
'no-var': 'error',
},
import 時に .ts
の拡張子が無いとエラー Error: error Missing file extension for "./MyModule" import/extensions
.ts
ファイルが拡張子なしでも import
できる設定が必要
.eslintrc.js
parserOptions: { project: './tsconfig.json', }, + settings: { + 'import/extensions': ['.js', '.jsx', '.ts', '.tsx'], + 'import/parsers': { + '@typescript-eslint/parser': ['.ts', '.tsx'], + }, + 'import/resolver': { + node: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + }, + }, rules: { + 'import/extensions': [ + 'error', + 'ignorePackages', + { js: 'never', jsx: 'never', ts: 'never', tsx: 'never' }, + ], 'import/prefer-default-export': 'off',
TypeScript のコンパイル設定
スプレッド構文 (e.g. [..."STRING"]
) でエラー Type 'XXXXX' is not an array type or a string type. Use compiler option '--downlevelIteration' to allow iterating of iterators.
[..."STRING👻"]
や [...document.querySelectorAll('span')]
のような書き方を許可するには downlevelIteration
オプションが必要
tsconfig.json
{ "compilerOptions": { "target": "es5" , "module": "commonjs, // target が es6 以下の場合は "dom.iterable" が必要 - "lib": [ "dom", "ES2017"], + "lib": [ "dom", "dom.iterable", "ES2017"], + "downlevelIteration": true,
Jest
Jest でテストを実行するための npm script を追加
package.json
"scripts": { "build:cjs": "tsc --project . --module commonjs --outDir ./dist-cjs", "build:esm": "tsc --project . --module esNext --outDir ./dist-esm", "build": "npm run build:cjs && npm run build:esm", + "test": "jest --runInBand", + "test:coverage": "jest test --coverage", "lint": "eslint \"src/**/*.{js,ts}\"", "lint:fix": "eslint --fix \"src/**/*.{js,ts}\"", "format": "prettier --write \"src/**/*.{js,ts}\"" }
パッケージのインストール
$ npm i --save-dev jest ts-jest @types/jest $ npx jest --init
jest.config.js
module.exports = { clearMocks: true, coverageProvider: 'v8', testEnvironment: "node", moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'node'], roots: ['<rootDir>/tests/'], transform: { '^.+.(js|jsx|ts|tsx)$': 'ts-jest' }, transformIgnorePatterns: ['/node_modules/', '\\.pnp\\.[^\\/]+$'], }
transform ではなく preset: 'ts-jest'
で TypeScript を有効にする
公式の Basic usage に従って preset: 'ts-jest'
を指定する方法に変更する
これを指定すると、よしなに transform してくれるっぽい
jest.config.js
module.exports = { clearMocks: true, coverageProvider: 'v8', + preset: "ts-jest", testEnvironment: "node", moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'node'], roots: ['<rootDir>/tests/'], - transform: { '^.+.(js|jsx|ts|tsx)$': 'ts-jest' }, transformIgnorePatterns: ['/node_modules/', '\\.pnp\\.[^\\/]+$'], }
cf.
Build 時にテストファイルを除く
この状態でビルドすると /tests
ディレクトリも含まれてしまうのでテストファイルはビルドから除外する。
ビルド用の設定ファイルを作成しビルド時はその設定を使うようにする
$ touch tsconfig.build.json
tsconfig.build.json
{ "extends": "./tsconfig.json", "exclude": ["tests/**/*", "**/?(*.)+(spec|test).[tj]s?(x)"] }
ビルド時に tsconfig.build.json
を使ってビルドするように変更
package.json
"scripts": { - "build:cjs": "tsc --project . --module commonjs --outDir ./dist-cjs", + "build:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist-cjs", - "build:esm": "tsc --project . --module esNext --outDir ./dist-esm", + "build:esm": "tsc --project tsconfig.build.json --module esNext --outDir ./dist-esm", "build": "npm run build:cjs && npm run build:esm" }
cf. typescript - Setting up tsconfig with spec/test folder - Stack Overflow
感想
まとめてたらめっちゃ時間掛かってしまった…
久しぶりに環境作ろうと思ったらエラーになりまくるのホントどうにかして欲しい…
と思ってテンプレートのリポジトリ作った
[参考]
- TypeScriptのプロジェクトにESLintとPrettierを併用してVSCodeの保存時に自動フォーマットをする | ZUMA Lab
- 決定版!イマドキの ESLint 設定! | DevelopersIO
- tsconfig
- TypeScript + ESLint
- VSCode
- Prettier + ESLint
- ESLint Roule
- import/prefer-default-export
- import/extensions
- Jest
- Exclude test files in build
- note.