TypeScript的枚舉與類型約束

●?上一章我們講了 TS 的接口
●?這一章, 我們就來聊一聊 TS 的枚舉和約束
枚舉
認(rèn)識(shí)枚舉
●?在很多計(jì)算機(jī)語言中都有枚舉的概念, 但是 JS 中是沒有枚舉這個(gè)概念的, 為了彌補(bǔ)這個(gè)缺憾 在 TS 加入了枚舉類型
●?什么是枚舉呢 ?
枚舉( mei ju ) : 枚舉的意思就是一一列舉, 把所有情況都列舉出來, 那么取值的時(shí)候, 只有這幾個(gè)可以使用, 其他的都不行
計(jì)算機(jī)語言里面的枚舉( enumerations ) : 把所有的常量放在一個(gè)集合內(nèi), 讓若干個(gè)常量變成一組有關(guān)聯(lián)的內(nèi)容

●?對(duì)于以上四個(gè)變量來說
●?我不管做任何邏輯, 我沒辦法限制你只能使用這四個(gè)變量中的一個(gè)
●?不管用什么方法, 你都沒辦法限制這個(gè) dir 參數(shù)接收到的必須是上面列出的四個(gè)方向
●?這個(gè)時(shí)候, 我們就可以用到枚舉了
●?首先, 在 TS 中, 利用 enum 關(guān)鍵字創(chuàng)建一個(gè)枚舉集合, 把我們需要的四個(gè)常量放進(jìn)去
●?制作了一個(gè) DIrection 枚舉集合, 那么就可以用這個(gè)集合來對(duì)某些數(shù)據(jù)進(jìn)行限制了
●?這就約定了, dir 這個(gè)參數(shù)的值只能是 Direction 這個(gè)枚舉集合里面的常量, 其他都不行

●?只要你寫的不是 Direction 這個(gè)枚舉內(nèi)的內(nèi)容都不行
數(shù)字枚舉
●?數(shù)字枚舉 : 枚舉類型中的每一個(gè)常量都是數(shù)字
●?在 TS 中, 枚舉內(nèi)的每一個(gè)常量, 當(dāng)你不設(shè)置值的時(shí)候, 默認(rèn)就是 number 類型
●?你在枚舉內(nèi)的常量, 第一個(gè)默認(rèn)值是 0, 后面的依次 +1 遞增
此時(shí)
Pages.ONE => 0
Pages.TWO => 1
Pages.THREE => 2
●?我們也可以自己指定值
●?這個(gè)時(shí)候枚舉集合內(nèi)的常量就是我們指定好的值
●?我們也可以指定部分值
●?指定常量后面的未指定常量, 就會(huì)按照 +1 的規(guī)則一次遞增
字符串枚舉
●?字符串枚舉 : 枚舉集合中的每一個(gè)常量的值都是 string 類型
●?在 TS 內(nèi), 你必須要指定一個(gè)值, 才可能會(huì)出現(xiàn) string 類型
●?在 TS 中, 枚舉常量和任何內(nèi)容都是不一樣的, 包括原始字符串

●?這是因?yàn)? 在 TS 中, 枚舉內(nèi)的每一個(gè)常量都是一個(gè)獨(dú)一無二的值
●?所以當(dāng)你用枚舉去限定一個(gè)數(shù)據(jù)的時(shí)候, 用的時(shí)候也只能用枚舉內(nèi)的值
●?這樣也避免你因?yàn)槭终`出現(xiàn)的單詞錯(cuò)誤, 比如你會(huì)不會(huì)認(rèn)為 'form' 和 'from' 是一個(gè)單詞呢
異構(gòu)枚舉
●?異構(gòu)枚舉 : 其實(shí)就是在一個(gè)枚舉集合內(nèi)同時(shí)混合了數(shù)字枚舉和字符串枚舉
●?但是你大概率是不會(huì)這樣使用的, 因?yàn)槲覀冏鳛橐唤M數(shù)據(jù)的集合, 一般不會(huì)把數(shù)字和字符串混合在一起使用
●?在這里有一個(gè)點(diǎn)需要注意
因?yàn)樵诿杜e集合內(nèi), 當(dāng)某一個(gè) key 你沒有設(shè)置值的時(shí)候, 會(huì)默認(rèn)按照上一個(gè)的值 +1
所以如果前一個(gè)是 字符串枚舉, 那么下一個(gè)必須要手動(dòng)賦值, 不然會(huì)報(bào)錯(cuò)
如果前一個(gè)是 數(shù)字枚舉, 那么下一個(gè)可以不必要手動(dòng)賦值, 會(huì)按照上一個(gè) +1 計(jì)算
枚舉合并
●?在 TS 內(nèi)的枚舉, 是支持合并的
●?多個(gè)枚舉類型可以分開書寫, 會(huì)在編譯的時(shí)候自動(dòng)合并
●?這里定義的兩個(gè)枚舉都叫做 Direction, 會(huì)在編譯的時(shí)候自動(dòng)放在一起, 不會(huì)出現(xiàn)沖突
反向映射
●?TS 內(nèi)的數(shù)字枚舉, 在編譯的時(shí)候, 會(huì)同時(shí)將 key 和 value 分別顛倒編譯一次
●? 以這個(gè)為例, 他是如何進(jìn)行編譯的呢
●?編譯完畢的結(jié)果
●?也就是說, 我們?cè)?TS 內(nèi)使用的時(shí)候, 如果是數(shù)字枚舉
●?那么我們可以通過 key 得到對(duì)應(yīng)的數(shù)字, 也可以通過對(duì)應(yīng)的數(shù)字得到對(duì)應(yīng)的 key
常量枚舉
●?常量枚舉, 是在枚舉的基礎(chǔ)上再加上 const 關(guān)鍵字來修飾
●?會(huì)在編譯的時(shí)候, 把枚舉內(nèi)容刪除, 只保留編譯結(jié)果
●?并且對(duì)于數(shù)字枚舉來說, 不在支持反向映射能力, 只能利用 key 來訪問
●?非常量枚舉
○?編譯完畢的 js 文件

●?常量枚舉
○?編譯完畢的 js 文件

類型約束
●?在 TS 中, 還有一個(gè)很神奇的關(guān)鍵字, 叫做 type
●?type 又叫做類型別名有很多神奇的功能, 不僅能支持 interface 定義的對(duì)象結(jié)構(gòu), 還支持任何手寫類型
●?先來看一個(gè)很簡(jiǎn)單的例子

●?觀察上面一段代碼, 我們定義了 n1 和 n2 和 n3 三個(gè)變量
○?對(duì)于類型的限制都是 number 或者 string 或者 boolean
●?寫起來的時(shí)候就非常麻煩
●?這個(gè)時(shí)候, 我們就可以使用 type 對(duì)其進(jìn)行別名設(shè)置
●?這樣一來, 我們的代碼是不是變得簡(jiǎn)潔了起來
●?可能小伙伴們認(rèn)為這個(gè)用的并不多, 但是 type 也不是只有這一個(gè)功能
type 的常見使用
●?基本類型的別名
○?這是一個(gè)非?;A(chǔ)的使用, 把 number 這個(gè)類型起了一個(gè)別名叫做 n
○?今后再用 n 來限制變量的時(shí)候, 其實(shí)就是在使用 number
●? 基本類型聯(lián)合
○?這就是聯(lián)合類型, 那 number 或者 string 這個(gè)類型齊了一個(gè)別名叫做 i
○?我們?cè)儆?i 來限制變量的時(shí)候, 這個(gè)變量就被限制為了 number 或者 string
●? 對(duì)象類型
○?這就是對(duì)象類型, 和 interface 很像, 用處基本一致
●?對(duì)象聯(lián)合類型
○?這就是對(duì)象聯(lián)合類型, 和 interface 的 extends 繼承很像
●?元組類型
●?常量限定
○?這個(gè) color 被限定為了幾個(gè)值, 將來用 color 去約束一個(gè)變量的時(shí)候
○?這個(gè)變量只能接受這幾個(gè)值, 這里和 enum 比較像了
type 和 interface 的共同點(diǎn)
1.? 都可以約束 對(duì)象 或者 函數(shù) 類型
○?interface
○?type
○?我們看到, 兩個(gè)定義方式略有區(qū)別, 但是后期用法基本一致
2.? 擴(kuò)展類型
○?interface 使用 extends 進(jìn)行繼承
○?type 使用 交叉(&) 來實(shí)現(xiàn)
3.? 聯(lián)合類型
○?interface 使用 extends 繼承 type
○?type 使用 交叉(&) 擴(kuò)展 interface
type 和 interface 的區(qū)別
1.? interface 支持多次聲明自動(dòng)合并, type 不支持
○?type 如果聲明重名標(biāo)識(shí)符會(huì)報(bào)錯(cuò)

2.? 對(duì)于 ES6 模塊化語法的默認(rèn)導(dǎo)出語法
○?interface 支持聲明的同時(shí)進(jìn)行默認(rèn)導(dǎo)出
○?type 必須先聲明, 在默認(rèn)導(dǎo)出
○?必須要先聲明好, 在進(jìn)行默認(rèn)導(dǎo)出, 如果直接連寫默認(rèn)導(dǎo)出, 會(huì)報(bào)錯(cuò)

3.? type 可以使用 typeof 關(guān)鍵字去獲取某一數(shù)據(jù)類型
○?這里定義了一個(gè) EleType 標(biāo)識(shí)符, 會(huì)自動(dòng)根據(jù) typeof 關(guān)鍵字檢測(cè)的 box 的類型限制
4.? type 支持使用 in 關(guān)鍵字去遍歷成映射類型