JavaScript 專案遷移到 TypeScript 步驟以及遇到的問題

暖生發表於2019-03-15

本文講述瞭如何將 JavaScript 專案遷移到 TypeScript 上,以及如何在專案中新增 TypeScript 配置,編寫 TypeScript 程式碼。

一、外掛安裝

安裝專案所需外掛,一般對應的模組都會有對應的 @types 外掛可以使用。不知道的是否需要安裝對應的 @types 外掛的話,可以到 TypeSearch 進行查詢。

# 安裝專案中使用的外掛
$ npm install typescript ts-jest ts-loader @types/enzyme @types/jest @types/node @types/react @types/react-dom --save-dev

# 安裝 tslint 相關外掛
$ npm install tslint tslint-config-prettier tslint-react --save

# 安裝 webpack 中對 typescript 支援的外掛
$ npm install fork-ts-checker-webpack-plugin tsconfig-paths-webpack-plugin --save-dev
複製程式碼

二、新增 tsconfig.json 配置檔案

在專案根目錄下新增 tsconfig.json 配置檔案。tsconfig.json檔案中指定了用來編譯這個專案的根檔案和編譯選項。

tsconfig.json

{
  "compilerOptions": {
    "baseUrl": ".",
    "outDir": "build/dist",
    "module": "commonjs",
    "target": "es5",
    "lib": ["es6", "dom"],
    "sourceMap": true,
    "allowJs": true,
    "jsx": "react",
    "moduleResolution": "node",
    "rootDir": "src",
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "experimentalDecorators": true
  },
  "exclude": [
    "config",
    "public",
    "node_modules",
    "build",
    "dist",
    "scripts",
    "acceptance-tests",
    "webpack",
    "jest",
    "src/setupTests.ts",
    "jest.config.js"
  ],
  "types": [
    "typePatches"
  ]
}
複製程式碼

再新增一個 tsconfig.prod.json 檔案,用來在專案生產環境配置中使用。

tsconfig.prod.json

{
  "extends": "./tsconfig.json"
}
複製程式碼

這裡直接繼承類 tsconfig.json 檔案中的內容。也可以新增一些不同的配置。


三、為專案新增 TsLint 配置檔案

在專案根目錄下新增 tslint.json 檔案。tslint.json 中配置了開發過程中的規則。

tslint.json

{
  "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"],
  "defaultSeverity": "warning",
  "rules": {
    // 物件屬性是否按照順序進行編寫
    "object-literal-sort-keys": false,
    // jsx 中是否允許使用 lambda 語法
    "jsx-no-lambda": false,
    // 引入模組是否需要按照字母順序
    "ordered-imports": false,
    // 不允許列印 console 
    "no-console": false,
    // 不允許隱式的依賴模組,比如引用別名中的模組
    "no-implicit-dependencies": false,
    // 是否必須使用 === 取代 ==
    "triple-equals": false,
    // 物件成員是否需要按照順序進行編寫
    "member-ordering": false
  },
  "linterOptions": {
    "exclude": [
      "config/**/*.js",
      "webpack/**/*.js",
      "node_modules/**/*.ts",
      "coverage/lcov-report/*.js",
      "src/**/*.js",
      "src/**/*.jsx"
    ]
  }
}
複製程式碼
  • extends:繼承了哪些規則
  • defaultSeverityTsLint 嚴重性等級,可以是 warning 或是 error
  • rules:配置規則,可以修改一些預設的 TsLint 規則
  • linterOptions.exclude:排除掉不需要進行 TsLint 檢查的檔案
  • 更多 TsLint 的規則配置可以參考 TsLint

四、在 webpack 配置檔案中新增 TypeScript 配置

在 webpack 開發環境中新增配置

使用外掛

在 webpack 配置檔案中使用外掛:

  • 在 plugins 中使用 ForkTsCheckerWebpackPlugin 外掛
  • 注意: 在 resolve.plugin 中使用 TsconfigPathsPlugin 外掛

webpack.config.dev.js

...
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
...

module.exports = {
    ...

    plugins: [
        new ForkTsCheckerWebpackPlugin({
            async: false,
            watch: path.resolve(__dirname, '../src'),
            tsconfig: path.resolve(__dirname, '../tsconfig.json'),
            tslint: path.resolve(__dirname, '../tslint.json')
        })
    ],
    resolve: {
        ...

        plugins: [
            new TsconfigPathsPlugin({ configFile: path.resolve(__dirname, '../tsconfig.json') })
        ],
        ...
    }
}
複製程式碼

在 webpack 中新增 TypeScript 的 rules 配置

使用 ts-loader

webpack.config.dev.js

...

module.exports = {
    ...
    rules: [
        {
            test: /\.(ts|tsx)$/,
            include: path.resolve(__dirname, '../src'),
            use: [
                {
                    loader: require.resolve('ts-loader'),
                    options: {
                        // disable type checker - we will use it in fork plugin
                        transpileOnly: true
                    }
                }
            ]
        },
        ...
    ],
    ...
}
複製程式碼

在 webpack 生產環境中新增配置

使用方式和上面 在 webpack 開發環境中新增配置 的方式一致。唯一不同的就是在使用外掛的時候,將 tsconfig.json 修改為 tsconfig.prod.json

webpack.prod.config.js

module.exports = {
    ...

    plugins: [
        new ForkTsCheckerWebpackPlugin({
            async: false,
            watch: path.resolve(__dirname, '../src'),
            tsconfig: path.resolve(__dirname, '../tsconfig.prod.json'),
            tslint: path.resolve(__dirname, '../tslint.json')
        })
    ],
    resolve: {
        ...

        plugins: [
            new TsconfigPathsPlugin({ configFile: path.resolve(__dirname, '../tsconfig.prod.json') })
        ],
        ...
    }
}
複製程式碼

五、遇到的問題

裝飾器使用問題

裝飾器使用問題
本來配置好的裝飾器,使用的好好的,配置完 TypeScript 之後,卻發現編輯器對應檔案裡面報紅線錯誤提示:

Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option to remove this warning.
複製程式碼

解決辦法:在根目錄下的 tsconfig.json 檔案裡面新增對應配置即可

tsconfig.json

{
    "compilerOptions": {
        "experimentalDecorators": true
    }
}
複製程式碼

生命週期提示紅線報錯問題

生命週期提示紅線報錯問題
使用函式方式建立元件沒有問題,使用類的方式建立時,生命週期函式下面都會報紅線提示錯誤:Parsing error: Unexpected token

解決辦法:將 VSCode 設定中的配置項進行修改即可

"eslint.validate": [
    "javascript",
    "javascriptreact",
    "typescript",
    // 下面這個對使用 ts 編寫的 React 元件進行 ESLint 的檔案檢查暫時先去掉  
    // "typescriptreact"	
]
複製程式碼

tsconfig.json 檔案內部報錯問題

tsconfig.json 檔案內部報錯問題
tsconfig.json 檔案內部報錯,第一行大括號那裡就出現錯誤,錯誤提示類似下面這種:

'c:/xxx/config/dev.js' is not under 'rootDir' 'c:/xxx/src'. 'rootDir' is expected to contain all source files."

JSON schema for the TypeScript compiler's configuration file
複製程式碼

這裡我 tsconfig.json 檔案中我配置的 rootDirsrc 目錄,但是在 exclude 屬性裡,我沒有將 src 的同級目錄 config 給排除,所以就會提示這個錯誤,在 tsconfig.json 中新增配置即可:

tsconfig.json

{
  "exclude": [
    ...
    "config"
  ],
}
複製程式碼

出現類似的問題,提示哪個目錄不在 rootDir 目錄下,就將哪個目錄新增到 exclude 屬性裡。

webpack 中配置的別名,在 ts 檔案中不識別的問題

webpack 中配置的別名,在 ts 檔案中不識別的問題
在 webpack 中為部分目錄配置了別名,可以直接目錄,會自動到對應目錄下尋找模組,在 js 檔案中可以正常使用,但是在 ts 檔案中卻會報錯:Cannot find module 'utils/xxx'

解決辦法:這時需要在 tsconfig.json檔案中單獨配置 paths 列表,對對應的路徑進行對映:

tsconfig.json

{
    "compilerOptions": {
        "baseUrl": ".",
        "paths": {
          "src/*": [
            "src/*"
          ],
          "utils/*": [
            "src/utils/*"
          ]
        }
	  },
    ...
}
複製程式碼

這樣啟動專案就不會再報錯,但是在 ts 檔案裡還是會有紅線報錯提醒,此時還需要在 tslint.json 檔案中新增 rules 配置:

tslint.json

{
    ...
    "rules": {
        "no-implicit-dependencies": false
    }
    ...
}
複製程式碼

TsconfigPathsPlugin 外掛位置配置錯誤問題

TsconfigPathsPlugin 外掛要配置在webpack 配置檔案中 resolve 屬性下的 plugins 裡,否則的話會有問題。比如,直接放在了 webpack 配置檔案中的 plugins 中就可能會出現兩個問題:

    1. 如果 tsconfig.json 檔案中 compilerOptions 屬性下沒有配置 baseUrl 屬性,就會提示 Found no baseUrl in tsconfig.json, not applying tsconfig-paths-webpack-plugin
    1. 然後配置 baseUrl 屬性 ,配置好之後還可能會報錯:`tsconfig-paths-webpack-plugin: No file system found on resolver. Please make sure you've placed the plugin in the correct part of the configuration. This plugin is a resolver plugin and should be placed in the resolve part of the Webpack configuration.

注意:所以 tsconfig-paths-webpack-plugin 外掛的位置一定要放在 webpack 配置檔案中 resolve 屬性下的 plugins 裡。

寫在後面

這就是目前在專案中新增的部分 TypeScript 以及 TsLint 配置。此時已經可以在專案中正常編寫 TypeScript 程式碼了。

如果大家在專案遷移的過程中如果遇到了別的問題,也可以拿出來交流探討一下。

相關文章