TypeScript | 當 TypeScript 遇上 React 的超級聯名 TSX 款

神Q超人
Enjoy life enjoy coding
9 min readJun 16, 2019
導入了 TypeScript 的 React Component

前言

Hi!大家好,我是神 Q 超人。其實標題應該是反過來了,因為我是先擁有一套完整的 React 專案架構,再硬是將 TypeScript 加進專案中,所以應該是 React 遇到 TypeScript 才對。

本文就是要記錄下過程,一是防範金魚腦的我將來忘記到底做了什麼,二是也希望能給想導入 TypeScript 的 React 工程師一個小參考 🙌 。

最後再提醒一下,文內說明的專案並非是 Create React App 架構,需要的東西全都是自己配置的,所以可能不適用於使用 Create React App 的讀者。

React 專案內容

這裡筆者擁有的 React 專案內容分成以下部分:

  1. Webpack 、 Babel : Webpack 負責打包所有套件及編譯, Babel 在編譯時負責轉換 ES6 及 JSX 的語法。
  2. SCSS : CSS 的預處理器,也有 loader 讓 Webpack 編譯。
  3. ESLint :約束語法規則。
  4. Jest :負責做單元測試。

這裡也提供初始的專案內容的 GitHub 讓大家 Clone ,他是跑得動的,也包含了上述架構,文章內也會依照此專案為基礎加上 TypeScript ,大家也可以依照需要來選擇修改哪個部分。

前置作業

因為筆者的 TypeScript 是直接裝在 Global 上,但還是記得另外裝在專案中,如果不想放 Global ,想只裝在該專案的 dev 也可以:

npm install typescript --save-dev

安裝完後需要產生 TypeScript 的 config file :

tsc --init

需要注意的是,如果 TypeScript 是安裝在 dev ,就不能直接執行上方的指令,而是要先將指令放入 package.json 的 script 中,再藉由 npm run 執行。

Webpack、Babel

這兩個把他們放在一起講,主要是下載 Babel 提供的 Presets ,讓 Webpack 可以抓到 .tsx 編譯:

npm install @babel/preset-typescript  --save-dev

下載後到 webpack.config.js 中,原本的 rule 內有針對 .js.jsxloader 設定,這裡將他們改成 .ts.tsx ,並在 presets 內加上剛剛下載的 @babel/preset-typescript

還有一個地方不能忘記,就是預設編譯的檔案在 entry 中是設置為 index.js ,也要改成 index.tsx

修改完第一個階段後,便可以將撰寫 Component 的 .js 檔案改成 .tsx , src目錄會變成:

src/
component/
Main/
index.scss
index.ts
Main.tsx
index.tsx

接著打開負責用 react-dom 將 Component 渲染到 HTML 的檔案(上圖中的 src/index.tsx ):

會發現 import 上紅通通的一片。

先來處理 react 和 react-dom 的部分,首先安裝 @types/react@types/react-dom ,因為專案裡改用了 TypeScript ,所以會檢測到原本的 react 和 react-dom 沒有指定型別,而這兩個套件可以為它們設置靜態型別,處理這個問題:

npm install @types/react @types/react-dom --save-dev

安裝完後可以看到他們變成綠色的了:

接下來是 import Component 的部分,這裡比較簡單,只需打開 tsconfig.json ,將 jsx 的設定打開:

但是這麼簡單的步驟我卻卡了很久,請大家記得要重開編輯器, TypeScript 才會重新檢查,重開後錯誤就只剩下 ESLint 的了:

ESLint 稍後再來做設定,那接下來可以嘗試用 webpack -p 編譯專案,應該會出現下列的錯誤:

那是因為, Webpack 預設只讀 .js 檔,所以突然冒出個 .ts 他是無法在目錄中找到的,所以打開 webpack.config.js 加上以下設置:

加上去後再執行一次 webpack -p ,就能成功了:

網頁上看起來也沒問題, CSS 也正確吃到:

但是當我們認為一切沒問題的時候,打開 Main.tsx ,卻發現 import CSS 的地方卻出現錯誤:

SCSS

第二階段,主要做的事是將 index.scss 轉換成 .ts 做匯出,讓其他的 .ts 檔案 import ,因此我們下載 typed-scss-modules ,他能夠替我們做到這件事:

npm install typed-scss-modules --save-dev

然後這裡也是千千萬萬要注意,如果你沒有用任何預處理器,純用 CSS 的話,就下載 typed-css-modules 就好了,否則是不會正確轉換的。

下載完後到 package.json 的 script 加上一行新指令:

tsm 後方的 src 是路徑,剛剛的套件會去找該路徑下所有的 .scss 檔案,將他編譯成能讓 .tsimport 的模組,現在我們用 npm run 執行他看看:

如果編譯成功,就會看見該目錄下新增了一個 index.scss.d.ts 的檔案,裡面會幫你將所有 ClassName 做 export

然後回到 Main.tsx ,會發現原本在 import 時會出現語法不正確的提示已經消失了:

如果覺得每一次修改都必須要記得編譯 .scss 很麻煩的話,他也有 watch 模式,讓 .scss 有異動時同時編譯,除此之外也可以設定他編譯後的命名方式,例如:camel (駱駝命名法)、 kebab (短橫線命名法)等等,都可以參考 GitHub 上的 README 介紹。

ESLint

這個階段是語法檢查, ESLint 可能有些不適合 .tsx 的檢查,例如剛剛編譯後的 SCSS , ESLint 就搞不懂冒號是在幹嘛:

因此要下載一個適用於 TypeScript 檢查的規則:

npm install eslint-plugin-typescript --save-dev
npm install @typescript-eslint/parser --save-dev

eslint-plugin-typescript 是依賴套件, @typescript-eslint/parser 是主要的 Parser 。

下載完後到 ESLint 的設定檔 .eslintrc.js ,加上以下的設定:

記得要重新打開編輯器,讓 ESLint 重新跑一遍,跑完後就能看到原本提示有問題的地方消失了:

Jest

終於到測試了,但是這裡先緩著點,畢竟我們的 Main ,都還是用純純正正的 .jsx ,只要把副檔名遮住沒人知道他其實是 .tsx

因此需要對他進行個大改造,這裡先快速帶過,之後會用其他文章介紹,畢竟重點是在於如何使用 Jest 測試 TypeScript ,所以戴上無限手套的我彈指間,讓 Main 變成這樣:

現在 Main 已經完全 TypeScript 化了,那執行測試會發生什麼事:

哎呀!出現了華麗的錯誤!

這一部份最簡單,因為測試不經過 Webpack 編譯,他是直接吃 .babelrc.js 的設定編譯,所以只需要替他加上剛剛下載的 @babel/preset-typescript 就行了:

加上後再執行一次測試,就能成功囉:

其實整個過程是不難的,但是因為專案內使用了許多不同的套件,所以當時在導入時常常這個過了又出現下一個問題,但幸好 StackOverflow 真的很給力,所以導入時間沒有很長,就可以讓專案順利地跑起來了。

如果文章中有任何問題或是講解不清楚的地方,再麻煩留言告知,我會盡快修改或回覆的,謝謝大家!

參考文章

  1. https://stackoverflow.com/questions/43595555/webpack-cant-resolve-typescript-modules
  2. https://medium.com/@shihKai/react-typescript-webpack-%E5%88%9D%E5%BF%83%E8%80%85%E8%BC%95%E9%AC%86%E5%BB%BA%E7%BD%AE%E6%94%BB%E7%95%A5-8caaa32cc474
  3. https://juejin.im/post/5a7803335188257a5d2b0fed
  4. https://juejin.im/entry/5a156adaf265da43231aa032

--

--