[TypeScript] 將TypeScript 導入到React專案 — 起手式

施慶銓
8 min readApr 20, 2023

--

該文章是為了記錄第一次使用TypeScript, 也是第一次將TypeScript 導入React的專案. 不過這個React 專案並非大型的專案, 只是只有幾個簡單頁面的React 專案, 所以可能在遭遇相容性的問題還沒辦法遇到太深入的問題, 不過至少因為這是個比較簡單的專案, 所以之後如果遇到更大型的React 專案也需要導入TypeScript, 勢必也會有很大的機會會遇到

目前我的React 專案是用CRA(Create-React App)工具並使用預設的設定建立, 所以專案預設的檔案都是js 為主. 如entry file: src/index.js, src/App.js ,專案設定檔也是使用 jsconfig.json

// App.js

import logo from './logo.svg';
import './App.css';

function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}

export default App;
// jsconfig.json
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}

在這專案中常見的檔案跟開發行為是

  • JSX
  • React Router
  • prop-types 檢查prop 的型別
  • jsconfig.json
  • JSON file import
  • SVG圖片匯入

另外, 因為習慣使用Tailwind CSS 的開發方式, 所以也加入Tailwind CSS 來管理CSS

為什麼加入TypeScript

不管是自己的專案, 或是公司的專案中, 很容易遇到幾個問題

  1. Function 的參數不知道是什麼型別. 而常常會被變數名稱誤導, 例如某個變數叫做portNumber, 但實際上卻是傳入string 型別, 而在port list 的各個port中, 這些port的number 屬性卻是number 型別, 導致常常做錯誤的型別判斷(portNumber === port.number)
  2. 引用錯誤的property. 比較常見的就是容易發生在相似的變數名稱上, 例如wanStatus /wanPortStatus. 或許乍看之下這兩個名稱應該要描述同一件事情, 但在不同人開發時, 可能命名的意義就不一樣, 也許wanStatus中沒有包含IP資訊而wanPortStatus才有, 此時在專案沒有妥善的管理下, 造成同一個檔案內同時出現這些類似的變數名稱, 此時TypeScript 能在complie time時期就能提早發現問題. 避免到runtime時期才發現錯誤

TypeScript的好處

  1. 參數的型別檢查
  2. 透過IDE的型別提示與屬性提示, 避免引用不存在的property.
  3. 取代 prop-types 工具來檢查component的參數型別以及參數可允許設定的值.
  4. 強制開發者做null/undefined 情況下的判斷. 當使用.find等之類的方法時, 開發者以為能正確取得值但實際上是拿到null, 而繼續把回傳值當作正常的物件操作時, 就容易出現錯誤

TypeScript除了可以完美解決專案容易遇到的兩個問題之外, 也帶來了原本沒遇預期的效益.

TypeScript的成本

  1. 學習曲線
  2. 開發習慣

其中學習曲線佔整個學習成本的一大部分.

  1. 不僅是需要在各個component 內加入型別
  2. 另外也需要熟習如何定義interface/type
  3. interface/type的使用方式.
  4. interface/type 差異
  5. 除了JS基本型別外, 要如何定義客製化型別, 如客製化的元件, 第三方元件, DOM元件等等
  6. 編譯問題(圖片解析/外部檔案匯入/ JavaScript各版本的語法解析)

評估

學習曲線固然高, 而且在整合時也一定會遇到許多相容性問題. 不過幸好剛好手邊有一個比較小的專案可以嘗試. 也算是可以先體驗TypeScript的開發模式, 所以一方面搭配的網路的文章, 一方面可以利用最近火紅的AI程式- ChatGPT 來減少我找解決方式的時間, 也說是降低了不小的門檻. 所以就姑且試試看

起手式

在CRA 的官網中, 有一篇文章是在介紹如何將TypeScript 導入已開發的React 專案中

所以, 最一開始的做法就是按照官網上面的教學, 安裝必要的套件

To add TypeScript to an existing Create React App project, first install it:

npm install --save typescript @types/node @types/react @types/react-dom @types/jest

or

yarn add typescript @types/node @types/react @types/react-dom @types/jest

Next, rename any file to be a TypeScript file (e.g. src/index.js to src/index.tsx) and restart your development server!

再來就是將各個檔案的副檔名改成typescript 相關, 如

  • .js => .ts
  • .jsx => .tsx

jsconfig.json 改成tsconfig.json, 因為現在這個專案已經是TypeScript, 所以要跟VSCode說現在要用TypeScript角度來看整個專案

或是可以透過指令(參考自React 官方文件中的TypeScript 介紹, 其中有提供以下指令的說明: Configuring the TypeScript Compiler)

npx -p typescript tsc --init

這指令是會將TypeScript安裝在全域環境, 並自動產生tsconfig.json, 裡面也有基本的設定

這也是接下來最煩瑣, 也是最令人挫折的地方

透過上面React官網的介紹, 底下也有提供一些連結來幫助新手導入TypeScripe

其中我覺得最有幫助的應該是第三個連結React + TypeScript Cheatsheets

透過這個連結可以找到這個網站

有完整的React+TypeScript的使用方式以及推薦的作法, 如interface與type的使用時機

TL;DR​

Use Interface until You Need Type — orta.

More Advice​

Here’s a helpful rule of thumb:

always use interface for public API's definition when authoring a library or 3rd party ambient type definitions, as this allows a consumer to extend them via declaration merging if some definitions are missing.

consider using type for your React Component Props and State, for consistency and because it is more constrained.

後記

接下來會繼續記錄我在加入TypeScript 發生的常見錯誤, 如同在文章一開始所提到的, 因為在這個小專案中碰到的問題, 之後可能在做更大的專案時也可能容易遇到, 所以之後會繼續用文章紀錄各個遇到的問題

--

--

施慶銓
施慶銓

No responses yet