typescript-eslint の consistent-type-imports が壊れる問題
fixableなので、勝手について Happy
typescript-eslint が提供するconfiguration({recommended,strict,stylistic}{,-type-checked}など)には含まれていないので、自分で設定する必要がある
ある日突然 import の type を付け忘れるとESLint(正確にはnext lint)が落ちるようになった
ルールで怒られるのではなく、Lintの実行が失敗する
エディタ上でもESLintが動かなくなってしまった
ターミナルには以下のように表示されていた
code:txt
Cannot read properties of undefined (reading 'length')
Occurred while linting ファイル名
Rule: "@typescript-eslint/consistent-type-imports"
!?
どこかで (undefinedが入った変数).length をしていそう
node_modules の中のファイルをいじって .length してそうな箇所にconsole.logを入れてみる?
具体的にはnode_modules/@typescript-eslint/eslint-plugin/dist/rules/consistent-type-imports.js
.lengthで検索してみたら25個……いけるか?
けど関数のコールスタックの深いところでエラーが発生してたら面倒だな…
などなど、いろいろ考える
実行時に一緒に出てきた気になるメッセージに気づく
code:txt
=============
WARNING: You are currently running a version of TypeScript which is not officially supported by @typescript-eslint/typescript-estree.
You may find that it works just fine, or you may not.
SUPPORTED TYPESCRIPT VERSIONS: >=4.3.5 <5.3.0
YOUR TYPESCRIPT VERSION: 5.3.3
Please only submit bug reports when using the officially supported version.
=============
まだ @typescript-eslint/typescript-estree が TS 5.3 をサポートしていないのはおかしい
@typescript-eslint/typescript-estree の古いバージョンがインストールされているのでは?
それでなんかASTの構造が変わって死んでいるのでは?
package-lock.json を覗いてみる
code:json
"node_modules/@typescript-eslint/typescript-estree": {
"version": "5.62.0",
かなり古いバージョンが入ってる
このとき、typescript-eslint の最新バージョンは 6.19.0
ビンゴっぽい
これが原因では? という仮定を立てる
でもなんで @typescript-eslint/typescript-estree の古いバージョンがインストールされているんだろう?
yarn だったらこういうとき yarn why が使えるが、ここで使用していたのは npm
npm でのyarn why 相当をググってみても出てこない
最近まで該当コマンドが無かった
yarn why のググラビティが低すぎる
yarn VS npm みたいな記事ばっかり出てくる
ChatGPT に聞いたら npm ls だと教えてくれた
code:md
Anonymous:
what is yarn why equivalent in npm?
ChatGPT:
The equivalent of yarn why in npm is npm ls. This command in npm is used to list the installed packages and their dependencies, similar to how yarn why is used in Yarn to understand why a specific package is installed in your project.
For instance, if you want to know why a certain package is installed in your project using npm, you can run:
`bash
`
This command will show you a tree of dependencies that led to the installation of the specified package, providing insights similar to what yarn why offers in Yarn.
npm ls @typescript-eslint/typescript-estree してみる
npm lsはインストールされているパッケージとそのバージョンを表示するコマンド
code:txt
├─┬ @typescript-eslint/eslint-plugin@6.19.0
│ ├─┬ @typescript-eslint/parser@6.7.0
│ │ └── @typescript-eslint/typescript-estree@6.7.0
│ ├─┬ @typescript-eslint/type-utils@6.19.0
│ │ ├── @typescript-eslint/typescript-estree@6.19.0
│ │ └─┬ @typescript-eslint/utils@6.19.0
│ │ └── @typescript-eslint/typescript-estree@6.19.0 deduped
│ └─┬ @typescript-eslint/utils@6.19.0
│ └── @typescript-eslint/typescript-estree@6.19.0
├─┬ eslint-plugin-import-access@2.1.2
│ └─┬ @typescript-eslint/utils@6.2.1
│ └── @typescript-eslint/typescript-estree@6.2.1
└─┬ eslint-plugin-storybook@0.6.15
└─┬ @typescript-eslint/utils@5.62.0
└── @typescript-eslint/typescript-estree@5.62.0
実際には@typescript-eslint/typescript-estree についてはハイライトされて出力されていた
https://gyazo.com/0a4496938af65a995eac2150bad34a6e
なんか eslint-plugin-storybook の依存している@typescript-eslint/utils 古くない?
eslint-plugin-storybook を見てみる
Issue はあった
まだ更新されてない
本来はeslint-plugin-storybook にPRを出すなりするべきだが、Issueにしばらくメンテナらしき人からの返信もないことから、workaroundを考える
これ見た人は upvote 👍 してね
解決策:強制的に@typescript-eslint/typescript-estreeの最新版を使わせる!
package.json の "overrides"で孫の依存のパッケージのバージョンを固定できる
例えば、@typescript-eslint/typescript-estreeの6.x をインストールするには、こう書く
code:json
"overrides": {
"@typescript-eslint/typescript-estree": "^6.0.0"
},
package.jsonを更新後 npm iを忘れずに
もう一回Lintを実行する
code:txt
2:1 Error: All imports in the declaration are only used as types. Use import type. @typescript-eslint/consistent-type-imports
動いた🙌
TypeScript 5.3.3 はサポートしてないよ! というwarningも出てない!
解決!
でも残るギモン「最新バージョンと5.xと今との間でどこが変わって落ちたのか?」
consistent-type-imports ルールのソースコードを調べてみる
GitHub の blame で表示して、最近変更された .length を参照している箇所を調べる
287行目が怪しそう!
2か月前というそれっぽい期間
https://gyazo.com/9a35b742a6ae731c22d50dd0ad125925
該当コミット
TypeScript 5.3 から Import attributes が導入され、従来の Import assertion が非推奨になったことによる変更だった
code:ts
// Import assertion
import obj from "./something.json" assert { type: "json" };
// Import attributes
import obj from "./something.json" with { type: "json" };
この変更は、typescript-eslint の v6.11.0 から入ってるようだ
https://gyazo.com/d6a9be0e43680618705453f2823e75d1
じゃあインストールしていた typescript-eslint のバージョンが v6.10.x 以前だったらこのエラーは発生しなかったのか…
ASTの型定義は attributes というプロパティが追加されて、assertionsというプロパティは削除されたわけじゃなかった(deprecatedになっただけ)だからメジャーバージョンは上がらなかったんだね
まとめ
原因
eslint-plugin-storybookのdependenciesに引っ張られて @typescript-eslint/typescript-estreeの古いバージョンが入っていた
これにより、コードをパースしてできるASTは import attributes のプロパティが無いものであった
しかし、明示的にインストールしていた@typescript-eslint/eslint-pluginは最新のバージョンであった
最新バージョンの@typescript-eslint/eslint-pluginでは( TS 5.3 で depracatedになった機能を使わないために) import attributes のプロパティを参照していた
以上によって、存在しないプロパティを参照することになり、undefinedを参照して落ちていた
解決策
上記「解決策:強制的に@typescript-eslint/typescript-estreeの最新版を使わせる!」を参照
ただし、このやり方では eslint-plugin-storybook が最新版の(メジャーバージョンをまたぐ)typescript-eslint のパッケージを参照するため、今度はこっちが壊れるかも
今のところ壊れてはいないけど、不具合が起こったらこれを疑う