使用 ESLint 檢查 TypeScript 代碼
TypeScript 與 ESLint
ESLint 是一個代碼檢查工具,主要用來發現代碼錯誤、統一代碼風格,目前已被廣泛的應用于各種 JavaScript 項目中。
它通過插件化的特性極大的豐富了適用范圍,搭配 typescript-eslint-parser 之后,甚至可以用來檢查 TypeScript 代碼。
為什么需要 ESLint
TypeScript 除了是一個編譯 ts 文件的工具以外,還可以 作為一個靜態代碼檢查工具使用 。
TypeScript 會對文件進行語法解析,如果遇到一些語法錯誤,或使用了未定義的變量,則會報錯。
ESLint 也會對文件進行語法解析,它可以對一些代碼風格進行約束,發現未定義的變量,但是對于錯誤的屬性或方法引用,卻無能為力。
我們對同樣一段代碼分別運行 tsc 和 eslint ,會得到如下報錯信息:
let myName = 'Tom';console.log(
My name is ${myNane}
); console.log(My name is ${myName.toStrng()}
); console.log(My name is ${myName}
)// tsc 報錯信息: // // index.ts(3,27): error TS2552: Cannot find name 'myNane'. Did you mean 'myName'? // index.ts(4,34): error TS2551: Property 'toStrng' does not exist on type 'string'. Did you mean 'toString'? // // // eslint 報錯信息: // // /path/to/index.ts // 3:27 error 'myNane' is not defined no-undef // 5:38 error Missing semicolon semi // // ? 2 problems (2 errors, 0 warnings) // 1 errors, 0 warnings potentially fixable with the
--fix
option.</pre>
存在的問題 | tsc 是否報錯 | eslint 是否報錯 |
---|---|---|
myName 被勿寫成了 myNane | :white_check_mark: | :white_check_mark: |
toString 被勿寫成了 toStrng | :white_check_mark:? | :x: |
少了一個分號 | :x: | :white_check_mark: |
上例中,由于 eslint 無法識別 myName 存在哪些方法,所以對于拼寫錯誤的 toString 沒有檢查出來。而代碼風格的錯誤不影響編譯,故 tsc 沒有檢查出來。
未定義的變量兩者都能檢查出來。
值得注意的是, tsc 不僅檢查出來了代碼問題,還非常智能的給出了修改建議。
下面是 TypeScirpt 作為一個靜態代碼檢查工具,與 ESLint 的關系圖:
上圖中,TypeScript 與 ESLint 有重疊的部分,也有各自獨立的部分,雖然發現代碼錯誤比統一的代碼風格更重要,但是當一個項目越來越龐大,開發人員也越來越多的時候,代碼風格的約束還是必不可少的。
下面我們就來一步一步給 TypeScript 項目添加 ESLint 檢查。
安裝
ESLint 可以安裝在當前項目中或全局環境下,因為代碼檢查是項目的重要組成部分,所以我們一般會將它安裝在當前項目中。可以運行下面的腳本來安裝:
npm install eslint --save-dev
由于 ESLint 默認使用 Espree 進行語法解析,無法識別 TypeScript 的一些語法,故我們需要安裝 typescript-eslint-parser ,替代掉默認的解析器,別忘了同時安裝 typescript :
npm install typescript typescript-eslint-parser --save-dev
由于 typescript-eslint-parser 對一部分 ESLint 規則支持性不好,故我們需要安裝 eslint-plugin-typescript ,彌補一些支持性不好的規則。
npm install eslint-plugin-typescript --save-dev
創建配置文件
ESLint 需要一個配置文件來決定對哪些規則進行檢查,配置文件的名稱一般是 .eslintrc.js 或 .eslintrc.json 。
當運行 ESLint 的時候檢查一個文件的時候,它會首先嘗試讀取該文件的目錄下的配置文件,然后再一級一級往上查找,將所找到的配置合并起來,作為當前被檢查文件的配置。
我們在項目的根目錄下創建一個 .eslintrc.js ,內容如下:
module.exports = { parser: 'typescript-eslint-parser', plugins: [ 'typescript' ], rules: { // @fixable 必須使用 === 或 !==,禁止使用 == 或 !=,與 null 比較時除外 'eqeqeq': [ 'error', 'always', { null: 'ignore' } ], // 類和接口的命名必須遵守帕斯卡命名法,比如 PersianCat 'typescript/class-name-casing': 'error' } }
以上配置中,我們指定了兩個規則,其中 eqeqeq 是 ESLint 原生的規則(它要求必須使用 === 或 !== ,禁止使用 == 或 != ,與 null 比較時除外), typescript/class-name-casing 是 eslint-plugin-typescript 為 ESLint 增加的規則(它要求類和接口的命名必須遵守帕斯卡命名法,比如 PersianCat )。
規則的取值一般是一個數組(上例中的 eqeqeq ),其中第一項是 off 、 warn 或 error 中的一個,表示關閉、警告和報錯。后面的項都是該規則的其他配置。
如果沒有其他配置的話,則可以將規則的取值簡寫為數組中的第一項(上例中的 typescirpt/class-name-casing )。
關閉、警告和報錯的含義如下:
- 關閉:禁用此規則
- 警告:代碼檢查時輸出錯誤信息,但是不會影響到 exit code
- 報錯:發現錯誤時,不僅會輸出錯誤信息,而且 exit code 將被設為 1(一般 exit code 不為 0 則表示執行出現錯誤)
檢查一個 ts 文件
創建了配置文件之后,我們來創建一個 ts 文件看看是否能用 ESLint 去檢查它了。
創建一個新文件 index.ts ,將以下內容復制進去:
interface person { name: string; age: number; }let tom: person = { name: 'Tom', age: 25 };
if (tom.age == 25) { console.log(tom.name + 'is 25 years old.'); }</pre>
然后執行以下命令:
./node_modules/.bin/eslint index.ts則會得到如下報錯信息:
/path/to/index.ts 1:11 error Interface 'person' must be PascalCased typescript/class-name-casing 11:13 error Expected '===' and instead saw '==' eqeqeq? 2 problems (2 errors, 0 warnings)</pre>
上面的結果顯示,剛剛配置的兩個規則都生效了:接口 person 必須寫成帕斯卡命名規范, == 必須寫成 === 。
需要注意的是,我們使用的是 ./node_modules/.bin/eslint ,而不是全局的 eslint 腳本,這是因為代碼檢查是項目的重要組成部分,所以我們一般會將它安裝在當前項目中。
可是每次執行這么長一段腳本頗有不便,我們可以在 package.json 中添加一個 script 來簡化這個步驟:
{ "scripts": { "eslint": "eslint index.ts" } }這時只需執行 npm run eslint 即可。
檢查整個項目的 ts 文件
我們的項目源文件一般是放在 src 目錄下,所以需要將 package.json 中的 eslint 腳本改為對一個目錄進行檢查。由于 eslint 默認不會檢查 .ts 后綴的文件,所以需要加上參數 --ext .ts :
{ "scripts": { "eslint": "eslint src --ext .ts" } }此時執行 npm run eslint 即會檢查 src 目錄下的所有 .ts 后綴的文件。
在 VSCode 中集成 ESLint 檢查
在編輯器中集成 ESLint 檢查,可以在開發過程中就發現錯誤,極大的增加了開發效率。
要在 VSCode 中集成 ESLint 檢查,我們需要先安裝 ESLint 插件,點擊「擴展」按鈕,搜索 ESLint,然后安裝即可。
VSCode 中的 ESLint 插件默認是不會檢查 .ts 后綴的,需要在「文件 => 首選項 => 設置」中,添加以下配置:
{ "eslint.validate": [ "javascript", "javascriptreact", "typescript" ] }這時再打開一個 .ts 文件,將鼠標移到紅色提示處,即可看到這樣的報錯信息了:
使用已完善的配置
ESLint 原生的規則和 eslint-plugin-typescript 的規則太多了,而且原生的規則有一些在 TypeScript 中支持的不好,需要禁用掉。
這里我推薦使用 AlloyTeam ESLint 規則中的 TypeScript 版本 ,它已經為我們提供了一套完善的配置規則。
安裝:
npm install --save-dev eslint typescript typescript-eslint-parser eslint-plugin-typescript eslint-config-alloy在你的項目根目錄下創建 .eslintrc.js ,并將以下內容復制到文件中:
module.exports = { extends: [ 'eslint-config-alloy/typescript', ], globals: { // 這里填入你的項目需要的全局變量 // 這里值為 false 表示這個全局變量不允許被重新賦值,比如: // // jQuery: false, // $: false }, rules: { // 這里填入你的項目需要的個性化配置,比如: // // // @fixable 一個縮進必須用兩個空格替代 // 'indent': [ // 'error', // 2, // { // SwitchCase: 1, // flatTernaryExpressions: true // } // ] } };使用 ESLint 檢查 tsx 文件
如果需要同時支持對 tsx 文件的檢查,則需要對以上步驟做一些調整:
安裝 eslint-plugin-react
npm install --save-dev eslint-plugin-reactpackage.json 中的 scripts.eslint 添加 .tsx 后綴
{ "scripts": { "eslint": "eslint src --ext .ts,.tsx" } }VSCode 的配置中新增 typescriptreact 檢查
{ "eslint.validate": [ "javascript", "javascriptreact", "typescript", "typescriptreact" ] }使用 AlloyTeam ESLint 規則中的 TypeScript React 版本
AlloyTeam ESLint 規則中的 TypeScript React 版本
Troubleshootings
Cannot find module 'typescript-eslint-parser'
你運行的是全局的 eslint,需要改為運行 ./node_modules/.bin/eslint 。
cannot read property type of null
需要關閉 eslint-plugin-react 中的規則 react/jsx-indent 。
VSCode 沒有顯示出 ESLint 的報錯
- 檢查「文件 => 首選項 => 設置」中有沒有配置正確
- 檢查必要的 npm 包有沒有安裝
- 檢查 .eslintrc.js 有沒有配置
- 檢查文件是不是在 .eslintignore 中
如果以上步驟都不奏效,則可以在「文件 => 首選項 => 設置」中配置 "eslint.trace.server": "messages" ,按 Ctrl + Shift + U 打開輸出面板,然后選擇 ESLint 輸出,查看具體錯誤。