當使用 TypeScript + TSlint + Babel + Jest 搭建開發環境時,在開發過程當中偶爾會被 IDE 提示「沒法從新聲明塊範圍變量」,從而致使編譯出錯,報錯圖示以下:node
相關開發環境配置以下:typescript
之因此 tslint 會提示這個錯誤,是由於在 Commonjs 規範裏,沒有像 ESModule 能造成閉包的「模塊」概念,全部的模塊在引用時都默認被拋至全局,所以當再次聲明某個模塊時,TypeScript 會認爲重複聲明瞭兩次相同的變量進而拋錯。json
對於這個問題,最簡單的解決方法是在報錯的文件底部添加一行代碼:export {}
。這行代碼會「欺騙」tslint 使其認爲當前文件是一個 ESModule 模塊,所以不存在變量重複聲明的可能性。當使用這個方法時,記得這樣配置你的 tsconfig.json
文件:babel
{ "include": ["src", "demo"], "compilerOptions": { "module": "commonjs", "noImplicitReturns": true, "noUnusedLocals": true, "esModuleInterop": true, // important! "target": "esnext", "strict": true, "outDir": "app", "declaration": true, "sourceMap": true } }
其中 esMoudleInterop
這個配置容許文件中出現 export
關鍵字。閉包
當你覺得已經萬事大吉的時候,你會發現第二個問題又浮出水面:你沒法執行編譯後的 JavaScript 代碼!是的,由於 babel 雖然可以幫你成功轉譯了 TypeScript 代碼,可是並無幫你去掉,你 hack 上的 export
關鍵字,所以 node 會因爲沒法識別該關鍵字而報錯。app
此時你有兩個選擇:測試
刪除
export
關鍵字,忍受惱人的 IDE 提示,強行讓 babel 編譯;插件
幸運的是,這樣作真的行得通,由於 tslint 只是一個 「lint」,它只負責提示你哪裏有問題,你能夠強行忽略它。可是,當你使用 Jest 配合 TypeScript 進行測試時這樣作就行不通了,由於 Jest 會把 tslint 發現的錯誤當成沒法原諒的錯誤告訴你,這意味着,你別想開開心心的測試你的代碼,固然你還能夠選擇第二種解法:rest
寫一個 babel 插件,讓 babel 轉譯時去除
export
關鍵字;code
這樣你的 node 能夠識別轉譯後的代碼,你的 Jest 也再也不會抱怨什麼,一箭雙鵰!然而,你真的想要專門爲此寫一個插件嗎?
若是你的第一反應和我同樣是腦海中一個大大的 「NO!!!」,你應該繼續往下看了,其實咱們還有第三個方案:)
實際上,已經有一個 babel 插件能夠知足咱們得需求了:@babel/plugin-transform-modules-commonjs
,這就是咱們一直求之不得的東西。正如插件名所暗示的,它能夠將 ESModule 模塊轉換爲符合 Commonjs 規範的代碼,而通過個人測試,當遇到 export {}
這樣的表達式時,其轉譯的方案是:「直接忽略」!這正是咱們想要的效果!
就這樣,在你的 babel.config.js
中加入這個插件,TSlint 不會再抱怨什麼,Jest 可以乖乖測試,Node 也不會朝你大吼 "What the * export !!",整個世界都清淨了。
最後,再分享一下個人全套相關配置,但願大家再也不爲這個問題感到困擾 😉:
{ "include": ["src", "demo"], "compilerOptions": { "module": "commonjs", "noImplicitReturns": true, "noUnusedLocals": true, "esModuleInterop": true, "target": "esnext", "strict": true, "outDir": "app", "declaration": true, "sourceMap": true } }
module.exports = { roots: ['<rootDir>/src'], transform: { '^.+\\.tsx?$': 'ts-jest', }, testPathIgnorePatterns: ['/node_moudles/', './src/utils/test.ts'], }
module.exports = { presets: ['@babel/typescript'], plugins: [ '@babel/plugin-transform-modules-commonjs', '@babel/proposal-class-properties', '@babel/proposal-object-rest-spread', ], }