<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          TypeScript上手指南

          共 27996字,需瀏覽 56分鐘

           ·

          2021-08-27 09:56

          前言

          ?

          哈嘍,我是樹(shù)醬,今天分享一篇蛙人的typescript指南,自從vue3、還有社區(qū)一些開(kāi)源工具、組件庫(kù)等都開(kāi)始基于typescript開(kāi)發(fā),其自帶的"可選的靜態(tài)類型系統(tǒng)",可以使得當(dāng)我們?cè)趹?yīng)用程序運(yùn)行之前,通過(guò)編譯器就可以顯示有關(guān)任何潛在問(wèn)題的警告

          ?

          一、為什么要用TypeScript

          TypeScript可以讓我們開(kāi)發(fā)中避免一些類型或者一些不是我們預(yù)期希望的代碼結(jié)果錯(cuò)誤。xxx is not defined 我們都知道JavaScript錯(cuò)誤是在運(yùn)行中才拋出的,但是TypeScript錯(cuò)誤直接是在編輯器里告知我們的,這極大的提升了開(kāi)發(fā)效率,也不用花大量的時(shí)間去寫單測(cè),同時(shí)也避免了大量的時(shí)間排查Bug

          二、TypeScript優(yōu)缺點(diǎn)

          優(yōu)點(diǎn)

          • 一般我們?cè)谇昂蠖寺?lián)調(diào)時(shí),都要去看接口文檔上的字段類型,而TypeScript會(huì)自動(dòng)幫我們識(shí)別當(dāng)前的類型。節(jié)省了我們?nèi)タ?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">文檔或者network時(shí)間。這叫做類型推導(dǎo)(待會(huì)我們會(huì)講到)

          • 友好地在編輯器里提示錯(cuò)誤,避免代碼在運(yùn)行時(shí)類型隱式轉(zhuǎn)換踩坑。

          缺點(diǎn)

          • 有一定的學(xué)習(xí)成本,TypeScript中有幾種類型概念,interface接口class類enum枚舉generics泛型等這些需要我們花時(shí)間學(xué)習(xí)。

          • 可能和一些插件庫(kù)結(jié)合的不是很完美

          三、TypeScript運(yùn)行流程及JavaScript代碼運(yùn)行流程

          「1. JavaScript運(yùn)行流程如下,依賴NodeJs環(huán)境和瀏覽器環(huán)境」

          • JavaScript代碼轉(zhuǎn)換為JavaScript-AST
          • AST代碼轉(zhuǎn)換為字節(jié)碼
          • 運(yùn)算時(shí)計(jì)算字節(jié)碼

          「2. TypeScript運(yùn)行流程,以下操作均為TSC操作,三步執(zhí)行完繼續(xù)同上操作,讓瀏覽器解析」

          • TypeScript代碼編譯為 TypeScript-AST
          • 檢查AST代碼上類型檢查
          • 類型檢查后,編譯為JavaScript代碼
          • JavaScript代碼轉(zhuǎn)換為JavaScript-AST
          • AST代碼轉(zhuǎn)換為字節(jié)碼
          • 運(yùn)算時(shí)計(jì)算字節(jié)碼

          四、TypeScript和JavaScript區(qū)別

          只有搞懂了二者的區(qū)別,我們才可以更好的理解TypeScript

          類型系統(tǒng)特性JavaScriptTypeScript
          類型是如何綁定?動(dòng)態(tài)靜態(tài)
          是否存在類型隱式轉(zhuǎn)換?
          何時(shí)檢查類型?運(yùn)行時(shí)編譯時(shí)
          何時(shí)報(bào)告錯(cuò)誤運(yùn)行時(shí)編譯時(shí)

          類型綁定

          「JavaScript」

          JavaScript動(dòng)態(tài)綁定類型,只有運(yùn)行程序才能知道類型,在程序運(yùn)行之前JavaScript對(duì)類型一無(wú)所知

          「TypeScript」

          TypeScript是在程序運(yùn)行前(也就是編譯時(shí))就會(huì)知道當(dāng)前是什么類型。當(dāng)然如果該變量沒(méi)有定義類型,那么TypeScript會(huì)自動(dòng)類型推導(dǎo)出來(lái)。

          類型轉(zhuǎn)換

          「JavaScript」

          比如在JavaScript1 + true這樣一個(gè)代碼片段,JavaScript存在隱式轉(zhuǎn)換,這時(shí)true會(huì)變成number類型number(true)和1相加。

          「TypeScript」

          TypeScript中,1+true這樣的代碼會(huì)在TypeScript中報(bào)錯(cuò),提示number類型不能和boolean類型進(jìn)行運(yùn)算。

          何時(shí)檢查類型

          「JavaScript」

          JavaScript中只有在程序運(yùn)行時(shí)才能檢查類型。類型也會(huì)存在隱式轉(zhuǎn)換,很坑。

          「TypeScript」

          TypeScript中,在編譯時(shí)就會(huì)檢查類型,如果和預(yù)期的類型不符合直接會(huì)在編輯器里報(bào)錯(cuò)、爆紅

          何時(shí)報(bào)告錯(cuò)誤

          「JavaScript」

          JavaScript只有在程序執(zhí)行時(shí)才能拋出異常,JavaScript存在隱式轉(zhuǎn)換,等我們程序執(zhí)行時(shí)才能真正的知道代碼類型是否是預(yù)期的類型,代碼是不是有效。

          「TypeScript」

          TypeScript中,當(dāng)你在編輯器寫代碼時(shí),如有錯(cuò)誤則會(huì)直接拋出異常,極大得提高了效率,也是方便。

          五、TypeScript總共圍繞兩種模式展開(kāi)

          顯式注解類型

          舉個(gè)栗子

          let name: string = "前端娛樂(lè)圈";

          let age: number = 38;

          let hobby: string[] = ["write code""玩游戲"]

          顯式注解類型就是,聲明變量時(shí)定義上類型(官方話語(yǔ)就是「聲明時(shí)帶上注解」),讓我們一看就明白,哦~,這個(gè)name是一個(gè)string類型。

          推導(dǎo)類型

          舉個(gè)栗子

          let name = "前端娛樂(lè)圈"// 是一個(gè)string類型

          let age = 38;  // 是一個(gè)number類型

          let hobby = ["write code""玩游戲"// 是一個(gè)string數(shù)組類型

          推導(dǎo)類型就是去掉顯示注解,系統(tǒng)自動(dòng)會(huì)識(shí)別當(dāng)前值是一個(gè)什么類型的。

          六、安裝TypeScript && 運(yùn)行

          typescript

          全局安裝typescript環(huán)境。

          npm i -g typescript

          可是這只是安裝了typescript,那我們?cè)趺催\(yùn)行.ts文件呢,安裝完typescript我們就可以執(zhí)行tsc命令。

          如:我們的文件叫做index.ts,直接在命令行執(zhí)行tsc index.ts即可。然后就可以看到在目錄下編譯出來(lái)一個(gè)index.js,這就是tsc編譯完的結(jié)果。

          「index.ts」

          const userName: string = "前端娛樂(lè)圈" 

          運(yùn)行tsc index.ts,你可以看見(jiàn)在index.ts的同級(jí)下又生成一個(gè)index.js,如下就是編譯的結(jié)果文件index.js

          var userName = "前端娛樂(lè)圈"

          上面我們知道了運(yùn)行tsc命令就可以編譯生成一個(gè)文件,有的小伙伴覺(jué)得這樣太麻煩了,每次運(yùn)行只是編譯出來(lái)一個(gè)文件還不是運(yùn)行,還得用node index.js才可以運(yùn)行。不急我們接著往下看

          ts-node

          我們來(lái)看一下這個(gè)插件ts-node,這個(gè)插件可以直接運(yùn)行.ts文件,并且也不會(huì)編譯出來(lái).js文件。

          npm i ts-node

          // 運(yùn)行 ts-node index.ts

          講到這里我們了解了「為什么要用TypeScript」和它的「優(yōu)缺點(diǎn)」以及它的「運(yùn)行工作方式」

          那么接下來(lái)步入TypeScript基礎(chǔ)知識(shí)的海洋啦~,follow me。

          感覺(jué)有幫助的小伙伴可以關(guān)注一下:「前端娛樂(lè)圈」 公眾號(hào),謝謝啦~,每天更新一篇小技巧

          七、基礎(chǔ)知識(shí)

          1. 基礎(chǔ)靜態(tài)類型

          TypeScript中基礎(chǔ)類型跟我們JavScript中基礎(chǔ)類型是一樣的。只是有各別是Ts里面新出的。

          1. number

          const count: number = 18// 顯示注解一個(gè)number類型

          const count1 = 18// 不顯示注解,ts會(huì)自動(dòng)推導(dǎo)出來(lái)類型

          2. string

          const str: string = "前端娛樂(lè)圈"// 顯示注解一個(gè)string類型

          const str1 = "蛙人"// 不顯示注解,ts會(huì)自動(dòng)推導(dǎo)出來(lái)類型

          3. boolean

          const status: string = false; // 顯示注解一個(gè)string類型

          const status1 = true; // 不顯示注解,ts會(huì)自動(dòng)推導(dǎo)出來(lái)類型

          4. null

          const value: null = null;

          const value: null = undefined// 這一點(diǎn)null類型可以賦值undefined跟在 js中是一樣的,null == undefined

          5. undefined

          const value: undefined = undefined;

          const value: undefined = null// 這一點(diǎn)null類型可以賦值undefined跟在 js中是一樣的,null == undefined

          6. void

          估計(jì)到這有一些小伙伴可能對(duì)void這個(gè)比較陌生,以為只有TypeScript才有的。其實(shí)不是哈,在我們JavaScript就已經(jīng)存在void關(guān)鍵字啦,它的意思就是無(wú)效的,有的小伙伴可能看見(jiàn)過(guò)早些項(xiàng)目里面<a href="javascript: void(0)">這是控制a標(biāo)簽的跳轉(zhuǎn)默認(rèn)行為。你不管怎么執(zhí)行void方法它都是返回undefined

          那么在我們TypeScriptvoid類型是什么呢。它也是代表無(wú)效的,一般只用在「函數(shù)」上,告訴別人這個(gè)「函數(shù)」沒(méi)有返回值。

          function fn(): void {} // 正確

          function testFn(): void {
              return 1// 報(bào)錯(cuò),不接受返回值存在
          }

          function fn1(): void return undefined// 顯示返回undefined類型,也是可以的

          function fn2(): void return null// 顯示返回null類型也可以,因?yàn)?nbsp;null == undefined

          7. never

          never「一個(gè)永遠(yuǎn)不會(huì)有值的類型」或者也可以說(shuō)「一個(gè)永遠(yuǎn)也執(zhí)行不完的類型」,代表用于不會(huì)有值,undefinednull也算做是值。一般這個(gè)類型就不會(huì)用到,也不用。大家知道這個(gè)類型就行。

          const test: never = null// 錯(cuò)誤
          const test1: never = undefined // 錯(cuò)誤

          function Person(): never // 正確,因?yàn)樗姥h(huán)了,一直執(zhí)行不完
              while(true) {}
          }

          function Person(): never // 正確,因?yàn)檫f歸,永遠(yuǎn)沒(méi)有出口
              Person()
          }

          function Person(): never // 正確 代碼報(bào)錯(cuò)了,執(zhí)行不下去
              throw new Error()
          }

          8. any

          any這個(gè)類型代表「任何的」「任意的」。希望大家在項(xiàng)目中,不要大片定義any類型。雖然它真的好使,那這樣我們寫TypeScript就沒(méi)有任何意義了。

          let value: any = ""// 正確
          value = null // 正確
          value = {} // 正確
          value = undefined // 正確

          9. unknown

          unknown類型是我們TypeScript中第二個(gè)any類型,也是接受任意的類型的值。它的英文翻譯過(guò)來(lái)就是「未知的」,我們來(lái)看一下栗子

          let value: unknown = ""  
          value = 1;
          value = "fdsfs"
          value = null
          value = {}

          那現(xiàn)在肯定有小伙伴疑惑,誒,那它unknown相當(dāng)于是any類型,那二者的區(qū)別是什么。我們來(lái)看一下

          let valueAny: any = "";
          let valueUnknown: unknown = "";

          valueAny = "蛙人";
          valueUnknown = "前端娛樂(lè)圈"

          let status: null = false;
          status = valueAny; // 正確
          status = valueUnknown // 報(bào)錯(cuò),不能將unknown類型分配給null類型

          我們來(lái)看一下上面的,為什么any類型就能被賦值成功,而unknown類型不行呢,從它倆的意義來(lái)上看,還是有點(diǎn)區(qū)別的,any任何的,任意的、unknown未知的。所以你給unknown類型賦值任何類型都沒(méi)關(guān)系,因?yàn)樗緛?lái)就是未知類型嘛。但是你如果把它的unknown類型去被賦值一個(gè)null類型,這時(shí)人家null這邊不干了,我不接受unknown類型。

          說(shuō)白了一句話,別人不接受unknown類型,而unknown類型接受別人,哈哈哈哈。

          2. 對(duì)象靜態(tài)類型

          說(shuō)起對(duì)象類型,我們肯定都能想到對(duì)象包含{}數(shù)組函數(shù)

          1. object && {}

          其實(shí)這倆意思一樣,{}object表示非原始類型,也就是除numberstringbooleansymbolnullundefined之外的類型。

          const list: object = {} // 空對(duì)象

          const list1: object = null// null對(duì)象

          const list: object = [] // 數(shù)組對(duì)象

          const list: {} = {}
          list.name = 1 // 報(bào)錯(cuò) 不可更改里面的字段,但是可以讀取
          list.toString()

          2. 數(shù)組

          const list: [] = []; // 定義一個(gè)數(shù)組類型

          const list1: number[] = [1,2// 定義一個(gè)數(shù)組,里面值必須是number

          const list2: object[] = [null, {}, []] // 定義一個(gè)數(shù)組里面必須是對(duì)象類型的

          const list3: Array<number> = [1,2,3// 泛型定義數(shù)組必須是number類型,泛型我們待會(huì)講到

          3. 類

          // 類
          class ClassPerson = {
              name"前端娛樂(lè)圈"
          }

          const person: ClassPerson = new Person();
          person.xxx = 123// 這行代碼報(bào)錯(cuò),因?yàn)楫?dāng)前類中不存在該xxx屬性

          4. 函數(shù)

          // 函數(shù)
          const fn: () => string = () => "前端娛樂(lè)圈" // 定義一個(gè)變量必須是函數(shù)類型的,返回值必須是string類型

          3. 函數(shù)類型注解

          這里說(shuō)一下函數(shù)顯示注解和函數(shù)參數(shù)不會(huì)類型推導(dǎo)問(wèn)題。

          1. 函數(shù)返回類型為number

          function fn(a, b): number {
              return a + b;
          }
          fn(12)

          2. 函數(shù)void

          顯示注解為void類型,函數(shù)沒(méi)有返回值。

          function fn(): void {
              console.log(1)
          }

          3. 函數(shù)不會(huì)自動(dòng)類型推導(dǎo)

          可以看到下面的函數(shù)類型,不會(huì)自動(dòng)類型推導(dǎo),我們實(shí)參雖然傳入的1和2,但是形參方面是可以接受任意類型值的,所以系統(tǒng)也識(shí)別不出來(lái)你傳遞的什么,所以這里得需要我們顯示定義注解類型。

          function testFnQ(a, b{
              return a + b
          }
          testFnQ(1,2)
          微信截圖_20210824233905.png

          我們來(lái)改造一下。

          function testFnQ(a:number, b:number) {
              return a + b
          }
          testFnQ(1,2)
          微信截圖_20210825001425.png

          我們?cè)賮?lái)看一下參數(shù)對(duì)象顯示注解類型,也是在:號(hào)后面賦值每個(gè)字段類型即可。

          function testFnQ(obj : {num: number}{
              return obj.num
          }
          testFnQ({num18})

          4. 元組Tuple

          元組用于表示一個(gè)已知數(shù)組的數(shù)量和類型的數(shù)組,定義數(shù)組中每一個(gè)值的類型,一般不經(jīng)常使用。

          const arr: [string, number] = ["前端娛樂(lè)圈"1]

          const arr: [string, string] = ["前端娛樂(lè)圈"1// 報(bào)錯(cuò)

          5. 枚舉Enum

          Enum枚舉類型,可以設(shè)置默認(rèn)值,如果不設(shè)置則為索引。

          enum color {
              RED,
              BLUE = "blue",
              GREEN = "green"
          }

          // color["RED"] 0
          // color["BLUE"] blue

          像上面的colorRED沒(méi)有設(shè)置值,那么它的值則為0,如果BLUE也不設(shè)置的話那么它的值則是1,它們這里是遞增。如果設(shè)置值則是返回設(shè)置的值

          「注意這里還有一個(gè)問(wèn)題,直接來(lái)上代碼」

          通過(guò)上面學(xué)習(xí)我們知道了enum可以遞增值,也可以設(shè)置默認(rèn)值。但是有一點(diǎn)得注意一下,enum沒(méi)有json對(duì)象那樣靈活,enum不能在任意字段上設(shè)置默認(rèn)值。

          比如下面栗子,RED沒(méi)有設(shè)置值,然后BLUE設(shè)置了默認(rèn)值,但是GREEN又沒(méi)有設(shè)置,這時(shí)這個(gè)GREEN會(huì)報(bào)錯(cuò)。因?yàn)槟愕诙€(gè)BLUE設(shè)置完默認(rèn)值,第三又不設(shè)置,這時(shí)代碼都不知道該咋遞增了,所以報(bào)錯(cuò)。還有一種方案就是你給BLUE可以設(shè)置一個(gè)數(shù)字值,這時(shí)第三個(gè)GREEN不設(shè)置也會(huì)跟著遞增,因?yàn)槎际?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">number類型。

          // 報(bào)錯(cuò)
          enum color {
              RED,
              BLUE = "blue",
              GREEN
          }

          // good
          enum color {
              RED,    // 0
              BLUE = 4,  // 4
              GREEN      // 5
          }

          比如enum枚舉類型還可以反差,通過(guò)valuekey值。像我們json對(duì)象就是不支持這種寫法的。

          enum color {
              RED,    // 0
              BLUE = 4,  // 4
              GREEN      // 5
          }

          console.log(color[4]) // BLUE
          console.log(color[0]) // RED

          5. 接口Interface

          接口interface是什么,接口interface就是方便我們定義一處代碼,多處復(fù)用。接口里面也存在一些修飾符。下面我們來(lái)認(rèn)識(shí)一下它們吧。

          1. 接口怎么復(fù)用

          比如在講到這之前,我們不知道接口這東西,可能需要給對(duì)象定義一個(gè)類型的話,你可能會(huì)這樣做。

          const testObj: { name: string, age: number } = { name"前端娛樂(lè)圈"age18 }

          const testObj1: { name: string, age: number } = { name"蛙人"age18 }

          我們用接口來(lái)改造一下。

          interface Types {
              name: string, 
              age: number
          }

          const testObj: Types = { name"前端娛樂(lè)圈"age18 }

          const testObj1: Types = { name"蛙人"age18 }

          可以看到使用interface關(guān)鍵字定義一個(gè)接口,然后賦值給這兩個(gè)變量,實(shí)現(xiàn)復(fù)用。

          2. readonly修飾符

          readonly類型,只可讀狀態(tài),不可更改。

          interface Types {
              readonly name: string, 
              readonly age: number
          }

          const testObj: Types = { name"前端娛樂(lè)圈"age18 }

          const testObj1: Types = { name"蛙人"age18 }

          testObj.name = "張三" // 無(wú)法更改name屬性,因?yàn)樗侵蛔x屬性
          testObj1.name = "李四" // 無(wú)法更改name屬性,因?yàn)樗侵蛔x屬性

          3. ?可選修飾符

          可選修飾符以?定義,為什么需要可選修飾符呢,因?yàn)槿绻覀儾粚?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">可選修飾符,那interface里面的屬性都是必填的。

          interface Types {
              readonly name: string, 
              readonly age: number,
              sex?: string
          }

          const testObj: Types = { name"前端娛樂(lè)圈"age18}

          4. extends繼承

          我們的interface也是可以繼承的,跟「ES6」Class類一樣,使用extends關(guān)鍵字。

          interface Types {
              readonly name: string, 
              readonly age: number,
              sex?: string
          }

          interface ChildrenType extends Types { // 這ChildrenType接口就已經(jīng)繼承了父級(jí)Types接口
              hobby: []
          }
              
          const testObj: ChildrenType = { name"前端娛樂(lè)圈"age18, hobby: ["code""羽毛球"] }

          5. propName擴(kuò)展

          interface里面這個(gè)功能就很強(qiáng)大,它可以寫入不在interface里面的屬性。

          interface Types {
              readonly name: string, 
              readonly age: number,
              sex?: string,
          }

          const testObj: Types = { name"前端娛樂(lè)圈"age19hobby: [] } 

          上面這個(gè)testObj這行代碼會(huì)爆紅,因?yàn)?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">hobby屬性不存在interface接口中,那么我們不存在的接口中的,還不讓人家寫了?。這時(shí)候可以使用「自定義」就是上面的propName

          interface Types {
              readonly name: string, 
              readonly age: number,
              sex?: string,
              [propName: string]: any // propName字段必須是 string類型 or number類型。 值是any類型,也就是任意的
          }

          const testObj: Types = { name"前端娛樂(lè)圈"age19hobby: [] } 

          在運(yùn)行上面代碼,就可以看到不爆紅了~

          6. Type

          我們?cè)賮?lái)看一下Type,這個(gè)是聲明類型別名使的,別名類型只能定義是:基礎(chǔ)靜態(tài)類型對(duì)象靜態(tài)類型元組聯(lián)合類型

          ?

          注意:type別名不可以定義interface

          ?
          type Types = string;

          type TypeUnite = string | number

          const name: typeUnite = "前端娛樂(lè)圈"
          const age: typeUnite = 18

          1. 那么type類型別名和interface接口有什么區(qū)別呢

          1. type不支持interface聲明
          type Types = number
          type Types = string // 報(bào)錯(cuò), 類型別名type不允許出現(xiàn)重復(fù)名字

          interface Types1 {
              name: string
          }

          interface Types1 {
              age: number
          }

          // interface接口可以出現(xiàn)重復(fù)類型名稱,如果重復(fù)出現(xiàn)則是,合并起來(lái)也就是變成 { name:string, age: number }

          第一個(gè)Types類型別名type不允許出現(xiàn)重復(fù)名字,interface接口可以出現(xiàn)重復(fù)類型名稱,如果重復(fù)出現(xiàn)則是,合并起來(lái)也就是變 { name:string, age: number }

          「再來(lái)看一下interface另一種情況」

          interface Types1 {
              name: string
          }

          interface Types1 {
              name: number
          }

          可以看到上面兩個(gè)同名稱的interface接口,里面的屬性也是同名稱,但是類型不一樣。這第二個(gè)的Types1就會(huì)爆紅,提示:「后續(xù)聲明的接口,必須跟前面聲明的同名屬性類型必須保持一致」,把后續(xù)聲明的name它類型換成string即可。

          2. type支持表達(dá)式 interface不支持
          const count: number = 123
          type testType = typeof count

          const count: number = 123

          interface testType {
              [name: typeof count]: any // 報(bào)錯(cuò)
          }

          可以看到上面type支持表達(dá)式,而interface不支持

          3. type 支持類型映射,interface不支持
          type keys = "name" | "age"  
          type KeysObj = {
              [propName in keys]: string
          }

          const PersonObj: KeysObj = { // 正常運(yùn)行
              name"蛙人",
              age"18"


          interface testType {
              [propName in keys]: string // 報(bào)錯(cuò)
          }

          7. 聯(lián)合類型

          聯(lián)合類型|表示,說(shuō)白了就是滿足其中的一個(gè)類型就可以。

          const statusTest: string | number = "前端娛樂(lè)圈"

          const flag: boolean | number = true

          再來(lái)看一下栗子。我們用函數(shù)參數(shù)使用「聯(lián)合類型」看看會(huì)發(fā)生什么

          function testStatusFn(params: number | string{
              console.log(params.toFixed()) // 報(bào)錯(cuò)
          }

          testStatusFn(1)

          上面我們說(shuō)過(guò)了,函數(shù)參數(shù)類型不能類型自動(dòng)推導(dǎo),更何況現(xiàn)在用上「聯(lián)合類型」,系統(tǒng)更懵逼了,不能識(shí)別當(dāng)前實(shí)參的類型。所以訪問(wèn)當(dāng)前類型上的方法報(bào)錯(cuò)。

          接下來(lái)帶大家看一些類型保護(hù),聽(tīng)著挺高級(jí),其實(shí)這些大家都見(jiàn)過(guò)。別忘了記得關(guān)注:「前端娛樂(lè)圈」 公眾號(hào)哦,嘻嘻

          1. typeof

          function testStatusFn(params: number | string{
              console.log(params.toFixed()) // 報(bào)錯(cuò)
          }
          testStatusFn(1)

          「改造后」

          // 正常
          function testStatusFn(params: string | number{
              if (typeof params == "string") {
                  console.log(params.split)
              }

              if (typeof params == "number") {
                  console.log(params.toFixed)
              }
          }

          testStatusFn(1)

          2. in

          // 報(bào)錯(cuò)
          interface frontEnd {
              name: string
          }

          interface backEnd {
              age: string
          }

          function testStatusFn(params: frontEnd | backEnd{
              console.log(params.name)
          }

          testStatusFn({name"蛙人"})

          「改造后」

          // 正常
          function testStatusFn(params: frontEnd | backEnd{
              if ("name" in params) {
                  console.log(params.name)
              }

              if ("age" in params) {
                  console.log(params.age)
              }
          }

          testStatusFn({name"蛙人"})

          3. as 斷言

          // 報(bào)錯(cuò)
          interface frontEnd {
              name: string
          }

          interface backEnd {
              age: string
          }

          function testStatusFn(params: frontEnd | backEnd{
              console.log(params.name)
          }

          testStatusFn({name"蛙人"})

          「改造后」

          // 正常
          function testStatusFn(params: frontEnd | backEnd{
              if ("name" in params) {
                  const res = (params as frontEnd).name
                  console.log(res)
              }
              
              
              if ("age" in params) {
                  const res = (params as backEnd).age
                  console.log(res)
              }
          }

          testStatusFn({age118})

          8. 交叉類型

          交叉類型就是跟聯(lián)合類型相反,它用&表示,交叉類型就是兩個(gè)類型必須存在。這里還用上面的「聯(lián)合類型」的栗子來(lái)看下。

          interface frontEnd {
              name: string
          }

          interface backEnd {
              age: number
          }

          function testStatusFn(params: frontEnd & backEnd) {}

          testStatusFn({age: 118, name: "前端娛樂(lè)圈"})

          這里我們可以看到實(shí)參必須傳入兩個(gè)**接口(interface)**全部的屬性值才可以。「聯(lián)合類型」是傳入其中類型就可以。

          「注意:我們的接口interface出現(xiàn)同名屬性」

          interface frontEnd {
              name: string
          }

          interface backEnd {
              name: number
          }

          function testStatusFn(params: frontEnd & backEnd) {
              console.log(params)
          }

          testStatusFn({name: "前端"})

          上面我們兩個(gè)接口類型中都出現(xiàn)了同名屬性,但是類型不一樣,這時(shí)類型就會(huì)變?yōu)?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">never。

          微信截圖_20210825181810.png

          9. 泛型

          泛型是TypeScript中最難理解的了,這里我盡量用通俗易懂的方式講明白。

          function test(a: string | number, b: string | number{
              console.log(a, b)
          }
          test(1"前端娛樂(lè)圈")

          比如上面栗子,函數(shù)參數(shù)注解類型定義stringnumber,調(diào)用函數(shù)實(shí)參傳入也沒(méi)什么問(wèn)題,但是有個(gè)需求,就是實(shí)參我們「必須傳入同樣的類型」(傳入兩個(gè)number類型)。雖然上面這種「聯(lián)合類型」也可以實(shí)現(xiàn),但是如果我們要在加一個(gè)boolean類型,那么「聯(lián)合類型」還得在追加一個(gè)boolean,那這樣代碼太冗余了。

          這時(shí)就需要用到「泛型」了,「泛型」是專門針對(duì)不確定的類型使用,并且靈活。泛型的使用大部分都是使用<T>,當(dāng)然也可以隨便使用,如:<Test><Custom>都可以。

          function test<T>(a: T, b: T{
              console.log(a, b)
          }
          test<number>(1"前端娛樂(lè)圈"// 調(diào)用后面跟著尖括號(hào)這就是泛型的類型,這時(shí)報(bào)錯(cuò),因?yàn)樵谡{(diào)用的使用類型是number,所以只能傳入相同類型的

          test<boolean>(truefalse

          test<string>("前端娛樂(lè)圈""蛙人")

          上面這使用「泛型」就解決了我們剛才說(shuō)的傳入同一個(gè)類型參數(shù)問(wèn)題,但是「泛型」也可以使用不同的參數(shù),可以把調(diào)用類型定義為<any>

          function test<T>(a: T, b: T{
              console.log(a, b)
          }

          test<any>(1"前端娛樂(lè)圈")

          但是上面這種又有一種問(wèn)題,它可以傳入對(duì)象,但是如果我們只希望傳入number類型和string類型。那么我們「泛型」也給我們提供了**約束「類型。「泛型」使用extends進(jìn)行了」類型約束**,只能選擇stringnumber類型。

          function test<T extends number | stringY extends number | string>(a: T, b: Y{
              console.log(a, b)
          }

          test<number, string>(18"前端娛樂(lè)圈")

          test<string, number>("前端娛樂(lè)圈"18)

          這時(shí),傳入泛型時(shí)使用逗號(hào)分隔,來(lái)定義每一個(gè)類型希望是什么。記住,只有我們不確定的類型,可以使用泛型。

          10. 模塊

          TypeScript也支持importexport這里大多數(shù)小伙伴都知道,這里都不多講啦。

          // 導(dǎo)入

          import xxx, { xxx } from "./xxx"

          // 導(dǎo)出

          export default {}

          export const name = "前端娛樂(lè)圈"

          如有不明白的小伙伴,可以看我以前文章 聊聊什么是CommonJs和Es Module及它們的區(qū)別

          11. Class類

          ?

          以下這三個(gè)修飾符是在TypeScript類中才能使用,在JavaScript類中是不支持的。

          ?
          報(bào)錯(cuò).png

          1. public

          public的公共屬性,就是不管在的內(nèi)部還是外部,都可以訪問(wèn)該「屬性」「方法」。默認(rèn)定義的「屬性」「方法」都是public

          class Person {
           name = "前端娛樂(lè)圈";
           public age = 18;
          }
          const res = new Person();
          console.log(res.name, res.age) // 前端娛樂(lè)圈 18

          上面可以看到打印結(jié)果都能顯示出來(lái),name屬性沒(méi)有定義public公共屬性,所以里面定義的「屬性」「方法」默認(rèn)都是public定義。

          2. private

          private的私有屬性,只有在當(dāng)前里面才能訪問(wèn),當(dāng)前就是{}里面區(qū)域內(nèi)。在{}外面是不能訪問(wèn)private定義的「屬性」「方法」

          class Person {
           private name = "前端娛樂(lè)圈";
           private age = 18;
          }
          const res = new Person();
          console.log(res.name, res.age) // 這倆行會(huì)爆紅,當(dāng)前屬性為私有屬性,只能在類內(nèi)部訪問(wèn)

          class Scholl extends Person {
              getData() {
                  return this.username + "," + this.age
              }
          }
          const temp = new Scholl()
          console.log(temp.getData()) // 爆紅~,雖然繼承了Person類,但是private定義是只能在當(dāng)前類訪問(wèn),子類也不能訪問(wèn)。

          3. protected

          protected的保護(hù)屬性,只有在「當(dāng)前類」「子類」可以訪問(wèn)。也就是說(shuō)用protected屬性定義的「子類」也可以訪問(wèn)。

          class Person {
           protected username = "前端娛樂(lè)圈";
           protected age = 18;
          }
          const res = new Person();
          console.log(res.name, res.age) // 這倆行會(huì)爆紅,當(dāng)前屬性為私有屬性,只能在類內(nèi)部訪問(wèn)

          class Scholl extends Person {
              getData() {
                  return this.username + "," + this.age
              }
          }
          const temp = new Scholl()
          console.log(temp.getData()) // 前端娛樂(lè)圈,18。可以正常訪問(wèn)父類的屬性

          4. implements

          implements關(guān)鍵字只能在class中使用,顧名思義,實(shí)現(xiàn)一個(gè)新的類,從父級(jí)或者從接口實(shí)現(xiàn)所有的屬性和方法,如果在PersonAll類里面不寫進(jìn)去接口里面已有的屬性和方法則會(huì)報(bào)錯(cuò)。

          interface frontEnd {
              name: string,
              fn() => void
          }

          class PersonAll implements frontEnd {
              name"前端娛樂(lè)圈";
              
              fn() {
                  
              }
          }

          5. 抽象類

          抽象類使用abstract關(guān)鍵字定義。abstract抽象方法不能實(shí)例化,如果,抽象類里面方法是抽象的,那么本身的類也必須是抽象的,抽象方法不能寫函數(shù)體。父類里面有抽象方法,那么子類也必須要重新該方法。

          // 抽象類
          abstract class Boss {
              name = "秦";
              call() {} // 抽象方法不能寫函數(shù)體
          }

          class A extends Boss {
              call() {
                  console.log(this.name);
                  console.log("A")
              }
          }

          class B extends Boss {
              call() {
                   console.log("B")
              }
          }

          new A().call()

          該抽象類使用場(chǎng)景,比如A需求或者B需求正好需要一個(gè)公共屬性,然后本身還有一些自己的邏輯,就可以使用抽象類,抽象類只能在TypeScript中使用。

          12. 命名空間namespace

          我們學(xué)到現(xiàn)在可以看到,不知道小伙伴們發(fā)現(xiàn)沒(méi)有,項(xiàng)目中文件是不是不能有重復(fù)的變量(不管你是不是一樣的文件還是其它文件),否則就直接爆紅了。命名空間一個(gè)最明確的目的就是解決重名問(wèn)題。

          命名空間使用namespace關(guān)鍵字來(lái)定義,來(lái)看栗子吧。

          「index.ts」

          namespace SomeNameSpaceName { 
              const q = {}

              export interface obj {
                  name: string
              }
          }

          上面這樣,就定義好了一個(gè)命名空間,可以看到變量q沒(méi)有寫export關(guān)鍵字,這證明它是內(nèi)部的變量,就算別的.ts文件引用它,它也不會(huì)暴露出去。而interface這個(gè)obj接口是可以被全局訪問(wèn)的。

          「我們?cè)趧e的頁(yè)面訪問(wèn)當(dāng)前命名空間」

          1. reference引入

          /// <reference path="./index.ts" />
          namespace SomeNameSpaceName { 
           export class person implements obj {
            name: "前端娛樂(lè)圈"
           }
          }

          2. import

          export interface valueData {
               name: string
          }
          import { valueData } from "./xxx.ts"

          這時(shí)使用命名空間之后完全可以解決不同文件重名爆紅問(wèn)題。

          13. tsConfig.json

          這個(gè)tsconfig文件,是我們編譯ts文件,如何將ts文件編譯成我們的js文件。tsc -init這個(gè)命令會(huì)生成該文件出來(lái)哈。執(zhí)行完該命令,我們可以看到根目錄下會(huì)生成一個(gè)tsconfig.json文件,里面有一堆屬性。

          那么我們?cè)趺磳?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">ts文件編譯成js文件呢,直接執(zhí)行tsc命令可以將根目錄下所有的.ts文件全部編譯成.js文件輸出到項(xiàng)目下。

          更多配置文檔,請(qǐng)參考官網(wǎng)

          {
              // include: ["*.ts"] // 執(zhí)行目錄下所有的ts文件轉(zhuǎn)換成js文件
              // include: ["index.ts"] // 只將項(xiàng)目下index.ts文件轉(zhuǎn)換為js文件
              // files: ["index.ts"] // 跟include一樣,只執(zhí)行當(dāng)前數(shù)組值里面的文件,當(dāng)前files必須寫相對(duì)路徑
              // exclude: ["index.ts"] // exclude就是除了index.ts不執(zhí)行,其它都執(zhí)行
              
              compilerOptions: {
                  removeCommentstrue// 去掉編譯完js文件的注釋
                  outDir"./build"// 最終輸出的js文件目錄
                  rootDir"./src"// ts入口文件查找
              }
          }

          八、實(shí)用類型

          最后來(lái)說(shuō)一下實(shí)用類型,TypeScript標(biāo)準(zhǔn)庫(kù)自帶了一些實(shí)用類型。這些實(shí)用類都是方便接口Interface使用。這里只列舉幾個(gè)常用的,更多實(shí)用類型官網(wǎng)

          1. Exclude

          從一個(gè)類型中排除另一個(gè)類型,只能是「聯(lián)合類型」,從TypesTest類型中排除UtilityLast類型。

          「適用于:并集類型」

          interface UtilityFirst {
              name: string
          }

          interface UtilityLast {
              age: number
          }

          type TypesTest = UtilityFirst | UtilityLast;

          const ObjJson: Exclude<TypesTest, UtilityLast> = {
              name: "前端娛樂(lè)圈"
          }

          2. Extract

          Extract正好跟上面那個(gè)相反,這是選擇某一個(gè)可賦值的「聯(lián)合類型」,從TypesTest類型中只選擇UtilityLast類型。

          「適用于:并集類型」

          interface UtilityFirst {
              name: string
          }

          interface UtilityLast {
              age: number
          }

          type TypesTest = UtilityFirst | UtilityLast;

          const ObjJson: Extract<TypesTest, UtilityLast> = {
              age1
          }

          3. Readonly

          把數(shù)組或?qū)ο蟮乃袑傩灾缔D(zhuǎn)換為只讀的。這里只演示一下對(duì)象栗子,數(shù)組同樣的寫法。

          「適用于:對(duì)象、數(shù)組」

          interface UtilityFirst {
              name: string
          }

          const ObjJson: Readonly<UtilityFirst> = {
              name"前端娛樂(lè)圈"
          }
          ObjJson.name = "蛙人" // 報(bào)錯(cuò) 只讀狀態(tài)

          4. Partial

          把對(duì)象的所有屬性設(shè)置為選的。我們知道interface只要不設(shè)置?修飾符,那么對(duì)象都是必選的。這個(gè)實(shí)用類可以將屬性全部轉(zhuǎn)換為可選的。

          「適用于:對(duì)象」

          interface UtilityFirst {
              name: string
          }

          const ObjJson: Partial<UtilityFirst> = {
              
          }

          5. Pick

          Pick選擇對(duì)象類型中的部分key值,提取出來(lái)。第一個(gè)參數(shù)目標(biāo)值,第二個(gè)參數(shù)「聯(lián)合」key

          「適用于:對(duì)象」

          interface UtilityFirst {
              name: string,
              age: number,
              hobby: []
          }

          const ObjJson: Pick<UtilityFirst, "name" | "age"> = {
              name"前端娛樂(lè)圈",
              age18
          }

          6. Omit

          Omit選擇對(duì)象類型中的部分key值,過(guò)濾掉。第一個(gè)參數(shù)目標(biāo)值,第二個(gè)參數(shù)「聯(lián)合」key

          「適用于:對(duì)象」

          interface UtilityFirst {
              name: string,
              age: number,
              hobby: string[]
          }

          const ObjJson: Omit<UtilityFirst, "name" | "age"> = {
              hobby: ["code""羽毛球"]
          }

          7. Required

          Required把對(duì)象所有可選屬性轉(zhuǎn)換成必選屬性。

          「適用于:對(duì)象」

          interface UtilityFirst {
              name?: string,
              age?: number,
              hobby?: string[]
          }

          const ObjJson: Required<UtilityFirst> = {
              name: "蛙人",
              age: 18,
              hobby: ["code"]
          }

          8. Record

          創(chuàng)建一個(gè)對(duì)象結(jié)果集,第一個(gè)參數(shù)則是key值,第二個(gè)參數(shù)則是value值。規(guī)定我們只能創(chuàng)建這里面字段值。

          「適用于:對(duì)象」

          type IndexList = 0 | 1 | 2

          const ObjJson: Record<IndexList, "前端娛樂(lè)圈"> = {
              0"前端娛樂(lè)圈",
              1"前端娛樂(lè)圈",
              2"前端娛樂(lè)圈"


           參考資料

          [1]

          聊聊什么是CommonJs和Es Module及它們的區(qū)別: https://juejin.cn/post/6938581764432461854

          [2]

          官網(wǎng): https://www.tslang.cn/docs/handbook/compiler-options.html

          [3]

          官網(wǎng): https://www.typescriptlang.org/docs/handbook/utility-types.html

          [4]

          了不起的 TypeScript 入門教程: https://juejin.cn/post/6844904182843965453

          [5]

          TypeScript中文網(wǎng): https://www.tslang.cn/docs/handbook/basic-types.html


          請(qǐng)你喝杯?? 記得三連哦~

          1.閱讀完記得給?? 醬點(diǎn)個(gè)贊哦,有?? 有動(dòng)力

          2.關(guān)注公眾號(hào)前端那些趣事,陪你聊聊前端的趣事

          3.文章收錄在Github frontendThings 感謝Star?

          瀏覽 39
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  www插插插无码视频 | 人人操人人看人人 | 东京热一二三区 | 做爱污污短视屏在线观看 | 蜜桃成人无码AV在线观看一电影 |