從環境搭建到打包使用TypeScript

Qsy 發表於 2021-09-09

1、TypeScript是什麼

  • 以JavaScript為基礎構建的語言,一個JavaScript的超集
  • 對JS進行了擴充,向JS中引入型別的概念,並且新增了許多新的特性
  • 支援在任何支援JavaScript的平臺中執行
  • TS的最終目的是為了專案易維護,易書寫

2、TypeScript增加了什麼

  • 增加了型別,增加支援ES的新特性,增加ES不具備的新特性
  • 增加豐富的配置選項,相較於JS而言,TS擁有了靜態型別,更加嚴格的語法,更強大的功能,TS可以在程式碼執行前就完成程式碼的檢查,減小了執行時異常的機率
  • 相同的功能用TS的程式碼量遠大於JS實現,但由於TS的程式碼結構更加清晰,變數型別更加明確,在後期程式碼的維護中TS遠遠勝於JS

3、TypeScript環境的搭建

1、下載node.js

2、安裝node.js

3、使用npm全域性安裝typescript

  • 進入命令列
  • 輸入 npm install -g typescript

4、建立一個TS檔案

5、使用tsc對檔案進行編譯

  • 在檔案所在目錄開啟終端
  • 輸入 tsc xxx.ts

6、如果編輯器不能tsc編輯是沒有cmd的許可權,給命令列工具管理員許可權就可解決問題 附連結

4、TypeScript的基本型別

  • 型別宣告

型別宣告是TS非常重要的一個特點,通過型別宣告可以指定TS中變數、形參、實參的型別,指定型別後,當為變數賦值時,TS編譯器會自動檢查值是否符合型別宣告,符合就賦值否則就報錯。總結:型別宣告給變數設定了型別,是的變數只能儲存某種型別的值

let 變數:型別
let 變數:型別 = 值
function fn(形參:型別,形參:型別):型別{}//外面的型別限制了fn的返回值的型別

// never 表示永遠不會返回結果
function fnx(): never{
    throw new Error('報錯了!');
}
  • 自動型別判斷

    • TS擁有自動的型別判斷機制
    • 當對變數的宣告和賦值是同時進行的
    • 所以如果你的變數的宣告和賦值是同時進行的,可以省略型別宣告
  • 型別

    型別 例子 描述
    number 1,33,2.5 任意數字
    string 'hi',"hi",hi 任意字串
    boolean true、false 布林值true或false
    字面量 其本身 限制變數的值就是該字面量的值
    any * 任意型別
    unknown * 型別安全的any
    void 空值(undefined) 沒有值(或undefined)
    never 沒有值 不能是任何值
    object {name:'肉絲'} 任意的JS物件
    array [1,2,3] 任意JS陣列
    tuple [4,5] 元素,TS新增型別,固定長度陣列
    enum enum{A,B} 列舉,TS中新增型別
  • number

    • let decimal:number = 6 //十進位制
      let hex:number = 0xf00d //十六進位制
      let binary:number = 0b1010 //二進位制
      let octal:number = 0o744 //八進位制
      let big:bigint = 100n // 大位元組
      
  • boolean

    • let isDone:boolean = false
      
  • string

    • let color:string = 'blue'
      color = 'red'
      
      let fullNmae:string = `Bob Bobbington`
      let age:number = 37
      let sentence:string = `Hello , my name is ${fullname}`
      
      I'll be ${age + 1} years old next month
      
  • 字面量

    • 也可以使用字面量去指定變數的型別,通過字面量可以確定變數的取值範圍

    • let color:'red' | 'blue' | 'black'
      let num:1 | 2 | 3 | 4 | 5 ;
      
  • any

    • let d:any = 4
      d = 'hello'
      d = true
      // 存在的問題是變數d可以賦值給其他變數
      
  • unknown

    • let unusable:unknown = undefined
      
  • never

    • function error(message:string):never {
      	throw new Error(message)
      }
      
  • object (沒啥用)

    • let obj:object = {}
      
  • tuple

    • 元組,規定了元素的型別順序必須完全對照的

    • let x: [string,number]
      x = ["hello",10]
      
    • 元組型別允許在元素型別字尾一個 ? 來說明元素是可選的:

      • const list :[number,string?,boolean?]
        list = [1,'calm',true]
        list = [10,'calm']
        list = [10]
        
    • 元組型別的Rest使用

  • array

    • let list : number[] = [1,2,3]
      let list : Array<number> = [1,2,3]
      
  • 型別斷言

    • 有些情況下,變數的型別對於我們來說是很明確,但是TS編譯器卻並不清除,此時可以通過型別斷言來告訴編譯器變數的型別,斷言的兩種形式

      • 第一種

        • let someValue : unknown = "this is a string"
          let strLength : number = (someValue as string).length
          
      • 第二種

        • let someValue : unknown = "this is a string"
          let strLength : number = (<string>someValue).length
          

5、TypeScrip編譯選項

  • 自動編譯檔案

    • 編譯檔案時,使用-w命令後,TS編譯器會自動監視檔案的變化,並在檔案發生變化時對檔案進行重新編譯

      tsc example.ts -w 
      
  • 自動編譯整個專案

    • 如果直接使用tsc指令,則可以自動將當前專案下的所有的檔案編譯為js檔案,但是直接使用tsc命令的前提是要現在專案根目錄下建立一個ts配置檔案 tsconfig.json

    • TSCONFIG.JSON是一個JSON檔案,新增配置檔案後,只需tsc命令即可完成對整個專案的編譯

    • 配置選項

      • include

        • 定義希望被編譯檔案的所在的目錄

        • 預設值:["**/*"]

        • 示例

          • "include":["src/**/*","test/**/*"]
            
          • 上述示例中,所有src目錄和tests目錄下的檔案都會被編譯

  • exclude

    • 定義需要排除在外的目錄

    • 預設值:["node_modules", "bower_components", "jspm_packages"]

    • 示例:

      • "exclude": ["./src/hello/**/*"]
        
      • 上述示例中,src下hello目錄下的檔案都不會被編譯

  • extends

    • 定義被繼承的配置檔案

    • 示例:

      • "extends": "./configs/base"
        
      • 上述示例中,當前配置檔案中會自動包含config目錄下base.json中的所有配置資訊

  • files

    • 指定被編譯檔案的列表,只有需要編譯的檔案少時才會用到

    • 示例:

      • "files": [
            "core.ts",
            "sys.ts",
            "types.ts",
            "scanner.ts",
            "parser.ts",
            "utilities.ts",
            "binder.ts",
            "checker.ts",
            "tsc.ts"
          ]
        
      • 列表中的檔案都會被TS編譯器所編譯

    • compilerOptions

      • 編譯選項是配置檔案中非常重要也比較複雜的配置選項

      • 在compilerOptions中包含多個子選項,用來完成對編譯的配置

        • 專案選項

          • target

            • 設定ts程式碼編譯的目標版本

            • 可選值:

              • ES3(預設)、ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext
            • 示例:

              • "compilerOptions": {
                    "target": "ES6"
                }
                
              • 如上設定,我們所編寫的ts程式碼將會被編譯為ES6版本的js程式碼

          • lib

            • 指定程式碼執行時所包含的庫(宿主環境)

            • 可選值:

              • ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext、DOM、WebWorker、ScriptHost ......
            • 示例:

              • "compilerOptions": {
                    "target": "ES6",
                    "lib": ["ES6", "DOM"],
                    "outDir": "dist",
                    "outFile": "dist/aa.js"
                }
                
          • module

            • 設定編譯後程式碼使用的模組化系統

            • 可選值:

              • CommonJS、UMD、AMD、System、ES2020、ESNext、None
            • 示例:

              • "compilerOptions": {
                    "module": "CommonJS"
                }
                
          • outDir

            • 編譯後檔案的所在目錄

            • 預設情況下,編譯後的js檔案會和ts檔案位於相同的目錄,設定outDir後可以改變編譯後檔案的位置

            • 示例:

              • "compilerOptions": {
                    "outDir": "dist"
                }
                
              • 設定後編譯後的js檔案將會生成到dist目錄

          • outFile

            • 將所有的檔案編譯為一個js檔案

            • 預設會將所有的編寫在全域性作用域中的程式碼合併為一個js檔案,如果module制定了None、System或AMD則會將模組一起合併到檔案之中

            • 示例:

              • "compilerOptions": {
                    "outFile": "dist/app.js"
                }
                
          • rootDir

            • 指定程式碼的根目錄,預設情況下編譯後檔案的目錄結構會以最長的公共目錄為根目錄,通過rootDir可以手動指定根目錄

            • 示例:

              • "compilerOptions": {
                    "rootDir": "./src"
                }
                
          • allowJs

            • 是否對js檔案編譯
          • checkJs

            • 是否對js檔案進行檢查

            • 示例:

              • "compilerOptions": {
                    "allowJs": true,
                    "checkJs": true
                }
                
          • removeComments

            • 是否刪除註釋
            • 預設值:false
          • noEmit

            • 不對程式碼進行編譯
            • 預設值:false
          • sourceMap

            • 是否生成sourceMap
            • 預設值:false
        • 嚴格檢查

          • strict
            • 啟用所有的嚴格檢查,預設值為true,設定後相當於開啟了所有的嚴格檢查
          • alwaysStrict
            • 總是以嚴格模式對程式碼進行編譯
          • noImplicitAny
            • 禁止隱式的any型別
          • noImplicitThis
            • 禁止型別不明確的this
          • strictBindCallApply
            • 嚴格檢查bind、call和apply的引數列表
          • strictFunctionTypes
            • 嚴格檢查函式的型別
          • strictNullChecks
            • 嚴格的空值檢查
          • strictPropertyInitialization
            • 嚴格檢查屬性是否初始化
        • 額外檢查

          • noFallthroughCasesInSwitch
            • 檢查switch語句包含正確的break
          • noImplicitReturns
            • 檢查函式沒有隱式的返回值
          • noUnusedLocals
            • 檢查未使用的區域性變數
          • noUnusedParameters
            • 檢查未使用的引數
        • 高階

          • allowUnreachableCode
            • 檢查不可達程式碼
            • 可選值:
              • true,忽略不可達程式碼
              • false,不可達程式碼將引起錯誤
          • noEmitOnError
            • 有錯誤的情況下不進行編譯
            • 預設值:false

6、TypeScrip的打包

通常情況下,實際開發中我們都需要使用構建工具對待嗎進行打包,TS同樣也可以結合構建工具一起使用,下邊以webpack為例介紹一下如何結合構建共建工具使用TS

  • 步驟

    • 1.初始化專案

      • 進入專案目錄,執行命令 npm init -y
      • 主要作用:建立package.json
    • 2.下載構建工具

      • npm i -D webpack-cli webpack-dev-server typescript ts-loader clean-webpack-plugin
      • 共安裝七個包分別是
        • webpack :構建工具
        • webpack-cli :webpack的命令列工具
        • webpack-dev-server :webpakc的開發伺服器
        • typescript :ts的編譯器
        • ts-loader :ts載入器,在webpack中編譯ts檔案
        • html-webpack-pluigin :webpakc中html外掛,用來自動建立html檔案
        • clean-webpakc-plugin : webpack中的清除外掛,每次構建都會先清除目錄
    • 3.根目錄檔案下建立webpack的配置檔案webpack.config.js

      const path = require("path")
      const HtmlWebpackPlugin = require("html-webpack-plugin")
      const {cleanWbpackPlugin} = require("clean-webpack-plugin")
      module.exports = {
          optimization:{
              minimize: false // 關閉程式碼壓縮,可選
          },
      
          entry: "./src/index.ts",
          
          devtool: "inline-source-map",
          
          devServer: {
              contentBase: './dist'
          },
      
          output: {
              path: path.resolve(__dirname, "dist"),
              filename: "bundle.js",
              environment: {
                  arrowFunction: false // 關閉webpack的箭頭函式,可選
              }
          },
      
          resolve: {
              extensions: [".ts", ".js"]
          },
          
          module: {
              rules: [
                  {
                      test: /\.ts$/,
                      use: {
                         loader: "ts-loader"     
                      },
                      exclude: /node_modules/
                  }
              ]
          },
      
          plugins: [
              new CleanWebpackPlugin(),
              new HtmlWebpackPlugin({
                  title:'TS測試'
              }),
          ]
      
      }
      
    • 4.根目錄下建立tsconfig.json,配置可以根據自己需要

      {
      	"complierOptions":{
      		"target":"ES2015",
      		"module": "ES2015",
              "strict": true
      	}
      }
      
    • 5.修改package.json新增如下配置

      {
        ...略...
        "scripts": {
          "test": "echo \"Error: no test specified\" && exit 1",
          "build": "webpack",
          "start": "webpack serve --open chrome.exe"
        },
        ...略...
      }
      
    • 6.在src下建立ts檔案,並在命令列執行 npm run build程式碼進行編譯,或者執行 npm start 來啟動開發伺服器

配置後的完整webpack.config.js截圖

image-20210909153606339

package.json的完整配置

image-20210909153731465

7、TypeScrip的相容性

通過一系列的配置,TS和webpack已經打包在了一起,實際開發中除了webpack還需要結合babel來對程式碼進行轉換以使其可以相容更多的瀏覽器,在上述步驟的基礎上,在通過下步驟再講babel引入到專案中

1 . 安裝依賴包

  • npm i -D @babel/core @babel/preset-env babel-loader core-js
  • 共安裝了4個包,分別是:
    • @babel/core
      • babel的核心工具
    • @babel/preset-env
      • babel的預定義環境
    • @babel-loader
      • babel在webpack中的載入器
    • core-js
      • core-js用來使老版本的瀏覽器支援新版ES語法

2.修改webpack.config.js配置檔案

module: {
    rules: [
        {
            test: /\.ts$/,
            use: [
             //ts結尾的檔案用兩個loader,分別對應兩個物件的配置
                {
                    loader: "babel-loader",
                    options:{
                        presets: [
                            [
                                "@babel/preset-env",
                                {
                                    "targets":{
                                        "chrome": "58",
                                        "ie": "10"
                                    },
                                    "corejs":"3",
                                    "useBuiltIns": "usage"
                                }
                            ]
                        ]
                    }
                },
                {
                    loader: "ts-loader",

                }
            ],
            exclude: /node_modules/
        }
    ]
}

配置成功之後,使用TS編譯的檔案會被tsloader和babel處理,是的程式碼可以在大部分瀏覽器中直接使用,可以在配置選項的targets中指定要相容的瀏覽器版本,針對ie我們一般只相容到10