# 從 JavaScript 到 TypeScript,React 項(xiàng)目遷移幾點(diǎn) tips

相對于 JavaScript,TypeScript 增加了類型系統(tǒng)。通過靜態(tài)檢查,開發(fā)者可以更早地發(fā)現(xiàn)語法錯誤,同時類型標(biāo)注也帶來了清晰的文檔。這篇文章記錄了幾個關(guān)于 React 項(xiàng)目從 JavaScript 遷移到 TypeScript 筆者處理過的一些問題,這些問題雖然并不復(fù)雜,但是如果在遷移的過程中遇到了,也需要花上不少的時間去調(diào)查和尋找解決方案。

首先推薦閱讀微軟的一篇 React 項(xiàng)目遷移文檔。

簡單總結(jié)一下,整個遷移的過程可以分為下面兩類操作:

  1. 配置 TypeScript 編譯器。
  2. 將 JavaScript 文件轉(zhuǎn)化為 TypeScript 文件。

配置編譯器

1. 安裝依賴

依賴可以分為兩類,一類是 TypeScript 編譯工具,另一類是第三方依賴的類型聲明文件(declarations)。

安裝編譯工具,TypeScript 的主流 loader 有 ts-loader 和 awesome-typescript-loader.

npm install --save-dev typescript ts-loader source-map-loader

安裝第三方依賴類型文件,下面的例子只包括了 react 和 react-dom,其他依賴聲明可以根據(jù)自己項(xiàng)目進(jìn)行安裝。

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

如果最終發(fā)布的內(nèi)容是會被其他項(xiàng)目引用的工具,應(yīng)該把 @types 包括在發(fā)布的文件當(dāng)中,即 npm i @types/xxx,如果發(fā)布的內(nèi)容不會被其他項(xiàng)目引用,那么安裝為 devDependencies 即可,可以參考 stackoverflow 上的這篇討論

如果項(xiàng)目開發(fā)時使用了熱更新(HMR),類型檢查會報(bào)錯 module.hot 類型問題,需要安裝 @types/webpack-env 來解決這個類型問題。

2. webpack 配置更新

  • 添加 resolve 的文件后綴:
resolve: {
  // changed from extensions: [".js", ".jsx"]
  extensions: [".ts", ".tsx", ".js", ".jsx"]
},
  • 使用 ts-loader 處理 js, jsx, ts, tsx 文件:
module: {
  rules: [
    // changed from { test: /\.jsx?$/, use: { loader: 'babel-loader' } },
    {
      test: /\.(t|j)sx?$/,
      use: {
        loader: ts-loader',
         options: { // options for spped up compilation
           transpileOnly: true
         }
       }
    },
    // addition - add source-map support
    { enforce: "pre", test: /\.js$/, loader: "source-map-loader" }
  ]
},

項(xiàng)目冷啟動開發(fā)時(npm start),如果順序進(jìn)行類型檢查和編譯,會花費(fèi)不少的時間。我們可以另開一個線程來進(jìn)行類型檢查,從而節(jié)約時間。fork-ts-checker-webpack-plugin 就是這樣一個 webpack plugin,非常推薦使用。

3. 添加 ts 編譯器配置

// tsconfig.js
{
    "compilerOptions": {
        "outDir": "./dist/",
        "sourceMap": true,
        "noImplicitAny": true,
        "strictNullChecks": true,
        "module": "es6",
        "target": "es5",
        "jsx": "react",
        "allowJs": true,
        "moduleResolution": "node",
        "allowSyntheticDefaultImports": true
    },
    "includes": [
      "./src/",
    ]
}

在之前的打包配置里面,babel 實(shí)現(xiàn)的功能主要有兩項(xiàng),包括:編譯 jsx 語法(preset-react)和 將晚進(jìn)的語法編譯為 es5 語法(preset-env),從而實(shí)現(xiàn)更好的兼容性。而 TypeScript 編譯器同樣可以實(shí)現(xiàn)這些操作,那么如果 babel 配置沒有其他特殊操作(比如編譯其他特殊語法),那么完全可以使用 TypeScript loader 替代 babel。

tsconfig 文件里面可以配置編譯器的各種選項(xiàng)。如果類型檢查的時候,因?yàn)橐氲慕M件沒有 default export (通過 module.exports 輸出),可能會報(bào)錯,那么配置allowSyntheticDefaultImport 可以讓 ts 忽略引用報(bào)錯。

文件轉(zhuǎn)換

源代碼文件

從 .js 遷移到 .ts,主要是添加各種類型聲明。

一些小 tips:

  • 事件類型(event):可以使用 React 事件注釋:
export type InputEvent = React.ChangeEvent<HTMLInputElement>;
export type ButtonEvent = React.MouseEvent<HTMLButtonElement>;
  • 組件類型(element):組件可以用 JSX.Element 標(biāo)注。
  • 組件方法聲明問題,在 React 組件里面,有的時候會直接在 constructor 里面對創(chuàng)建的對象綁定方法:
constructor(props) {
  ...
  
  this.foo = () => {
    ...
  }
}

而下面這種方式是將方法聲明給了該組件 class 的 prototype,然后在 constructor 里面綁定新建對象。

constructor(props) {
  ...
  
  this.foo = this.foo.bind(this);
}

foo() {
  ...
}

這兩種寫法對于程序運(yùn)行沒有實(shí)際的區(qū)別,但是第一種方式聲明的方法并不在 prototype 上,所以類型檢查無法將生成對象的方法和 class 方法對應(yīng)起來,會報(bào)錯。解決方法是按照第二種寫法,將方法綁定到 class prototype 上即可。

樣式文件

對于預(yù)處理樣式(比如 stylus,sass,less等),需要相應(yīng)的 declarations 文件,通過配置 css-modules-typescript-loader 可以幫助我們自動生成 d.ts 文件。

  1. 安裝 css-modules-typescript-loader,在 webpack 配置其在 css-loader 之后處理樣式文件。
  2. 創(chuàng)建一個 declaration 文件,聲明預(yù)處理樣式文件命名格式,因?yàn)槲覀兊捻?xiàng)目文件名字采用 .cm.styl 后綴表示,所以聲明如下:
// declarations.d.ts
declare module '*.cm.styl';
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容