TypeScript 是 JavaScript 的一個超集,主要提供了類型系統和對 ES6 的支持,它由 Microsoft 開發,代碼開源於 GitHub 上。html
它的第一個版本發佈於 2012 年 10 月,經歷了屢次更新後,如今已成爲前端社區中不可忽視的力量。TypeScript是一種靜態類型語言,增長了代碼的可讀性和可維護性,應用愈來愈普遍。接下來,咱們來看下如何遷移本身的項目至TypeScript。前端
npm install typescript
複製代碼
TypeScript使用tsconfig.json
文件管理工程配置,例如你想包含哪些文件和進行哪些檢查。 讓咱們先建立一個簡單的工程配置文件:node
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"strictNullChecks": false,
"module": "commonjs",
"target": "ESNext",
"jsx": "react",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"moduleResolution": "node",
"allowJs": true
},
"include": [
"./src/**/*"
]
}
複製代碼
這裏咱們爲TypeScript設置了一些東西:react
讀取全部可識別的src
目錄下的文件(經過include
)。 接受JavaScript作爲輸入(經過allowJs
)。 生成的全部文件放在dist
目錄下(經過outDir
)。 ... 你能夠在這裏瞭解更多關於tsconfig.json
文件的說明。webpack
在工程根目錄下建立一個webpack.config.js
文件。git
module.exports = {
entry: './src/index.tsx',
output: {
filename: 'bundle.js',
path: `${__dirname}/dist`
},
// Enable sourcemaps for debugging webpack's output. devtool: "#source-map", resolve: { // Add '.ts' and '.tsx' as resolvable extensions. extensions: ['.js', '.ts', '.tsx'] }, module: { rules: [ // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'. { test: /\.tsx?$/, loader: 'awesome-typescript-loader', options: { useCache: true, // Use internal file cache useBabel: true, // Invoke Babel to transpile files babelCore: '@babel/core' } }, ] } }; 複製代碼
這裏咱們設置useBabel
爲true
, 調用babel生成文件。github
安裝須要的包web
npm install @babel/preset-typescript
複製代碼
將上面安裝的包加入工程目錄下的babel.config.js
文件。typescript
module.exports = {
presets: ["@babel/preset-typescript", '@babel/preset-react', '@babel/preset-env', 'mobx'],
plugins: [
...
]
}
複製代碼
準備工做完成。 終於能試試期待已久的TypeScript
了,心情好happy 😜 可是,等等,What?爲何報錯了?express
TS2304: Cannot find name 'If'.
TS2304: Cannot find name 'Choose'.
TS2304: Cannot find name 'When'.
複製代碼
原來是咱們在React
項目中使用了jsx-control-statements致使的。 怎麼辦?在線等,挺急的... 😜 咱們發現,這裏咱們能夠用tsx-control-statements來代替。
安裝
npm install tsx-control-statements
複製代碼
在tsconfig.json
文件的files
選項中添加
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"strictNullChecks": false,
"module": "commonjs",
"target": "ESNext",
"jsx": "react",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"moduleResolution": "node",
"allowJs": true
},
"files": [
"./node_modules/tsx-control-statements/index.d.tsx"
]
}
複製代碼
在webpack的配置文件webpack.config.js
中添加
const statements = require('tsx-control-statements').default;
module.exports = {
...
module: {
rules: [
// All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
{
test: /\.tsx?$/,
loader: 'awesome-typescript-loader',
options: {
useCache: true, // Use internal file cache
useBabel: true, // Invoke Babel to transpile files
babelCore: '@babel/core',
// Add tsx-control-statements here
getCustomTransformers: () => ({ before: [statements()] })
}
},
]
},
...
};
複製代碼
接下來咱們按照TypeScript官網指南來把咱們的代碼改爲TypeScript
就能夠了,這裏就不做詳細介紹了。
可是這就結束了麼,no no no... 在編譯過程當中,咱們發現有些包的導入有問題 好比,將i18next
做爲外部資源引用時(webpack
的externals
能夠幫助咱們實現該方式),咱們發現代碼被編譯成
i18next_1['default'].t
複製代碼
可是i18next_1['default']
的值是undefined
,執行出錯 爲何?哪裏又雙叒叕...有問題了?😭
ECMAScript模塊在ES2015裏才被標準化,在這以前,JavaScript生態系統裏存在幾種不一樣的模塊格式,它們工做方式各有不一樣。 當新的標準經過後,社區遇到了一個難題,就是如何在已有的「老式」模塊模式之間保證最佳的互通性。
TypeScript與Babel採起了不一樣的方案,而且直到如今,還沒出現真正地固定標準。 在以前的版本,TypeScript 對 CommonJs/AMD/UMD 模塊的處理方式與 ES6 模塊不一樣,這會致使一些問題:
import * as koa from 'koa'
與 const koa = require('koa')
等價,但使用 import * as
建立的模塊對象實際上不可被調用以及被實例化。import koa from 'koa'
與 const koa = require('koa').default
等價,但在大部分 CommonJs/AMD/UMD 模塊裏,它們並無默認導出。在 2.7 後的版本里,TypeScript提供了一個新的 esModuleInterop
標記,旨在解決上述問題。 當使用這個新的esModuleInterop
標記時,可調用的CommonJS模塊必須被作爲默認導入:
import express from "express";
let app = express();
複製代碼
咱們將其加入tsconfig.json
文件中
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"strictNullChecks": false,
"module": "commonjs",
"target": "ESNext",
"jsx": "react",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"allowSyntheticDefaultImports": true, // 容許使用 ES2015 默認的 import 風格
"esModuleInterop": true, // 可調用的CommonJS模塊必須被作爲默認導入,在已有的「老式」模塊模式之間保證最佳的互通性
"moduleResolution": "node",
"allowJs": true
},
"files": [
"./node_modules/tsx-control-statements/index.d.tsx"
]
}
複製代碼
到了這裏,咱們的程序終於能完美的運行起來了。 咱們不想再區分哪些須要使用import * as
,哪些使用import
,所以咱們將格式統一爲
import XX from 'XX'
複製代碼