成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

深入 TypeScript 中的子類(lèi)型、逆變、協(xié)變,進(jìn)階 Vue3 源碼前必須搞懂的

開(kāi)發(fā) 前端
TypeScript 中有很多地方涉及到子類(lèi)型 subtype、父類(lèi)型 supertype 的概念,如果搞不清這些概念,那么很可能被報(bào)錯(cuò)搞得無(wú)從下手,或者在寫(xiě)一些復(fù)雜類(lèi)型的時(shí)候看到別人可以這么寫(xiě),但是不知道為什么他可以生效。

 [[336024]]

本文轉(zhuǎn)載自微信公眾號(hào)「 前端從進(jìn)階到入院」,作者 ssh前端 。轉(zhuǎn)載本文請(qǐng)聯(lián)系 前端從進(jìn)階到入院公眾號(hào)。

前言

TypeScript 中有很多地方涉及到子類(lèi)型 subtype、父類(lèi)型 supertype 的概念,如果搞不清這些概念,那么很可能被報(bào)錯(cuò)搞得無(wú)從下手,或者在寫(xiě)一些復(fù)雜類(lèi)型的時(shí)候看到別人可以這么寫(xiě),但是不知道為什么他可以生效。(就是我自己沒(méi)錯(cuò)了)

子類(lèi)型

比如考慮如下接口:

  1. interface Animal { 
  2.   age: number 
  3.  
  4. interface Dog extends Animal { 
  5.   bark(): void 

在這個(gè)例子中,Animal 是 Dog 的父類(lèi),Dog是Animal的子類(lèi)型,子類(lèi)型的屬性比父類(lèi)型更多,更具體。

  • 在類(lèi)型系統(tǒng)中,屬性更多的類(lèi)型是子類(lèi)型。
  • 在集合論中,屬性更少的集合是子集。

也就是說(shuō),子類(lèi)型是父類(lèi)型的超集,而父類(lèi)型是子類(lèi)型的子集,這是直覺(jué)上容易搞混的一點(diǎn)。

記住一個(gè)特征,子類(lèi)型比父類(lèi)型更加具體,這點(diǎn)很關(guān)鍵。

可賦值性 assignable

assignable 是類(lèi)型系統(tǒng)中很重要的一個(gè)概念,當(dāng)你把一個(gè)變量賦值給另一個(gè)變量時(shí),就要檢查這兩個(gè)變量的類(lèi)型之間是否可以相互賦值。

  1. let animal: Animal 
  2. let dog: Dog 
  3.  
  4. animal = dog // ✅ok 
  5. dog = animal // ❌error! animal 實(shí)例上缺少屬性 'bark' 

從這個(gè)例子里可以看出,animal 是一個(gè)「更寬泛」的類(lèi)型,它的屬性比較少,所以更「具體」的子類(lèi)型是可以賦值給它的,因?yàn)槟闶侵?animal 上只有 age 這個(gè)屬性的,你只會(huì)去使用這個(gè)屬性,dog 上擁有 animal 所擁有的一切類(lèi)型,賦值給 animal 是不會(huì)出現(xiàn)類(lèi)型安全問(wèn)題的。

反之,如果 dog = animal,那么后續(xù)使用者會(huì)期望 dog 上擁有 bark 屬性,當(dāng)他調(diào)用了 dog.bark() 就會(huì)引發(fā)運(yùn)行時(shí)的崩潰。

從可賦值性角度來(lái)說(shuō),子類(lèi)型是可以賦值給父類(lèi)型的,也就是 父類(lèi)型變量 = 子類(lèi)型變量 是安全的,因?yàn)樽宇?lèi)型上涵蓋了父類(lèi)型所擁有的的一切屬性。

當(dāng)我初學(xué)的時(shí)候,我會(huì)覺(jué)得 T extends {} 這樣的語(yǔ)句很奇怪,為什么可以 extends 一個(gè)空類(lèi)型并且在傳遞任意類(lèi)型時(shí)都成立呢?當(dāng)搞明白上面的知識(shí)點(diǎn),這個(gè)問(wèn)題也自然迎刃而解了。

在函數(shù)中的運(yùn)用

假設(shè)我們有這樣的一個(gè)函數(shù):

  1. function f(val: { a: number; b: number }) 

有這樣兩個(gè)變量:

  1. let val1 = { a: 1 } 
  2. let val2 = { a: 1, b: 2, c: 3 } 

調(diào)用 f(val1) 是會(huì)報(bào)錯(cuò)的,比較顯而易見(jiàn)的來(lái)看是因?yàn)槿鄙賹傩?b,而函數(shù) f 中很可能去訪(fǎng)問(wèn) b 屬性并且做一些操作,比如 b.substr(),這就會(huì)導(dǎo)致崩潰。

換成上面的知識(shí)點(diǎn)來(lái)看,val1 對(duì)應(yīng)的類(lèi)型是{ a: number },它是 { a: number, b: number } 的父類(lèi)型,調(diào)用 f(val1) 其實(shí)就相當(dāng)于把函數(shù)定義中的形參 val 賦值成了 val1, 把父類(lèi)型的變量賦值給子類(lèi)型的變量,這是危險(xiǎn)的。

反之,調(diào)用 f(val2) 沒(méi)有任何問(wèn)題,因?yàn)?val2 的類(lèi)型是 val類(lèi)型的子類(lèi)型,它擁有更多的屬性,函數(shù)有可能使用的一切屬性它都有。

假設(shè)我現(xiàn)在要開(kāi)發(fā)一個(gè) redux,在聲明 dispatch 類(lèi)型的時(shí)候,我就可以這樣去做:

  1. interface Action { 
  2.   type: string 
  3.  
  4. declare function dispatch<T extends Action>(action: T) 

這樣,就約束了傳入的參數(shù)一定是 Action 的子類(lèi)型。也就是說(shuō),必須有 type,其他的屬性有沒(méi)有,您隨意。

在聯(lián)合類(lèi)型中的運(yùn)用

學(xué)習(xí)了以上知識(shí)點(diǎn),再看聯(lián)合類(lèi)型的可賦值性,乍一看會(huì)比較反直覺(jué), 'a' | 'b' | 'c' 是 'a' | 'b' 的子類(lèi)型嗎?它看起來(lái)屬性更多誒?其實(shí)正相反,'a' | 'b' | 'c' 是 'a' | 'b' 的父類(lèi)型。因?yàn)榍罢弑群笳吒笇挿骸梗笳弑惹罢吒妇唧w」。

  1. type Parent = 'a' | 'b' | 'c' 
  2. type Son = 'a' | 'b' 
  3.  
  4. let parent: Parent 
  5. let son: Son 
  6.  
  7. parent = son // ✅ok 
  8. son = parent // ❌error! parent 有可能是 'c' 

這里 son 是可以安全的賦值給 parent 的,因?yàn)?son 的所有可能性都被 parent 涵蓋了。

而反之則不行,parent 太寬泛了,它有可能是 'c',這是 Son 類(lèi)型 hold 不住的。

這個(gè)例子看完以后,你應(yīng)該可以理解為什么 'a' | 'b' extends 'a' | 'b' | 'c' 為 true 了,在書(shū)寫(xiě) conditional types的時(shí)候更加靈活的運(yùn)用吧。

逆變和協(xié)變

先來(lái)段維基百科的定義[1]:

協(xié)變與逆變(Covariance and contravariance )是在計(jì)算機(jī)科學(xué)中,描述具有父/子型別關(guān)系的多個(gè)型別通過(guò)型別構(gòu)造器、構(gòu)造出的多個(gè)復(fù)雜型別之間是否有父/子型別關(guān)系的用語(yǔ)。

描述的比較晦澀難懂,但是用我們上面的動(dòng)物類(lèi)型的例子來(lái)解釋一波,現(xiàn)在我們還是有 Animal 和 Dog 兩個(gè)父子類(lèi)型。

協(xié)變(Covariance)

那么想象一下,現(xiàn)在我們分別有這兩個(gè)子類(lèi)型的數(shù)組,他們之間的父子關(guān)系應(yīng)該是怎么樣的呢?沒(méi)錯(cuò),Animal[] 依然是 Dog[] 的父類(lèi)型,對(duì)于這樣的一段代碼,把子類(lèi)型賦值給父類(lèi)型依然是安全的:

  1. let animals: Animal[] 
  2. let dogs: Dog[] 
  3.  
  4. animals = dogs 
  5.  
  6. animals[0].age // ✅ok 

轉(zhuǎn)變成數(shù)組之后,對(duì)于父類(lèi)型的變量,我們依然只會(huì)去 Dog 類(lèi)型中一定有的那些屬性。

那么,對(duì)于 type MakeArray = T[] 這個(gè)類(lèi)型構(gòu)造器來(lái)說(shuō),它就是 協(xié)變(Covariance) 的。

逆變(Contravariance)

有這樣兩個(gè)函數(shù):

  1. let visitAnimal = (animal: Animal) => void; 
  2. let visitDog = (dog: Dog) => void; 

animal = dog 是類(lèi)型安全的,那么 visitAnimal = visitDog 好像也是可行的?其實(shí)不然,想象一下這兩個(gè)函數(shù)的實(shí)現(xiàn):

  1. let visitAnimal = (animal: Animal) => { 
  2.   animal.age 
  3.  
  4. let visitDog = (dog: Dog) => { 
  5.   dog.age 
  6.   dog.bark() 

由于 visitDog 的參數(shù)期望的是一個(gè)更具體的帶有 bark 屬性的子類(lèi)型,所以如果 visitAnimal = visitDog 后,我們可能會(huì)用一個(gè)不帶 bark 屬性的普通的 animal 類(lèi)型來(lái)傳給 visitDog。

  1. visitAnimal = visitDog 
  2.  
  3. let animal = { age: 5 } 
  4.  
  5. visitAnimal(animal) // ❌ 

這會(huì)造成運(yùn)行時(shí)錯(cuò)誤,animal.bark 根本不存在,去調(diào)用這個(gè)方法會(huì)引發(fā)崩潰。

但是反過(guò)來(lái),visitDog = visitAnimal 卻是完全可行的。因?yàn)楹罄m(xù)調(diào)用方會(huì)傳入一個(gè)比 animal 屬性更具體的 dog,函數(shù)體內(nèi)部的一切訪(fǎng)問(wèn)都是安全的。

在對(duì) Animal 和 Dog 類(lèi)型分別調(diào)用如下的類(lèi)型構(gòu)造器之后:

  1. type MakeFunction<T> = (arg: T) => void 

父子類(lèi)型關(guān)系逆轉(zhuǎn)了,這就是 逆變(Contravariance)。

在 TS 中

當(dāng)然,在 TypeScript 中,由于靈活性等權(quán)衡,對(duì)于函數(shù)參數(shù)默認(rèn)的處理是 雙向協(xié)變 的。也就是既可以 visitAnimal = visitDog,也可以 visitDog = visitAnimal。在開(kāi)啟了 tsconfig 中的 strictFunctionType 后才會(huì)嚴(yán)格按照 逆變 來(lái)約束賦值關(guān)系。

 

責(zé)任編輯:武曉燕 來(lái)源: 前端從進(jìn)階到入院
相關(guān)推薦

2009-08-03 18:24:28

C# 4.0協(xié)變和逆變

2022-04-18 20:12:03

TypeScript靜態(tài)類(lèi)型JavaScrip

2009-05-27 11:30:20

C#Visual Stud協(xié)變

2011-01-14 10:27:18

C#.netasp.net

2012-03-13 09:32:15

C#協(xié)變

2023-01-29 09:15:42

2020-09-17 07:08:04

TypescriptVue3前端

2021-05-26 10:40:28

Vue3TypeScript前端

2021-07-29 12:05:18

Vue3Api前端

2020-09-29 06:37:30

Java泛型

2021-12-08 09:09:33

Vue 3 Computed Vue2

2021-09-22 07:57:23

Vue3 插件Vue應(yīng)用

2021-11-19 09:29:25

項(xiàng)目技術(shù)開(kāi)發(fā)

2020-02-11 14:14:52

this函數(shù)

2020-10-25 18:43:20

VueTypeScript前端

2021-11-26 05:59:31

Vue3 插件Vue應(yīng)用

2021-12-13 00:54:14

組件Vue3Setup

2013-10-31 09:36:43

程序員程序高手

2022-11-01 11:55:27

ReactVue3

2024-03-22 08:57:04

Vue3Emoji表情符號(hào)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 一区视频在线 | www.99热| 成人av网站在线观看 | 精品1区2区3区4区 | 亚洲精品日韩精品 | 国产精品免费一区二区三区四区 | 国产精品久久久久久52avav | 91免费在线 | 中文字幕二区三区 | 国产精品久久久久久妇女6080 | 国产欧美精品在线 | 中文字幕精品一区久久久久 | 欧美日韩一区二区电影 | 99久久免费精品国产男女高不卡 | 亚洲欧美日韩精品久久亚洲区 | 欧美国产视频 | 一级片毛片 | 国产精品一区二区免费 | 免费观看av | 国产精品天堂 | 成人免费高清 | 亚洲天堂一区二区 | 黑人巨大精品欧美黑白配亚洲 | av大片在线观看 | 九色一区 | 欧美日韩国产一区二区 | 日韩av一区二区在线观看 | 欧美日韩在线一区二区三区 | 国产日韩欧美激情 | 999久久久久久久久6666 | 国产一二三区免费视频 | 精品影院| 国产日韩视频在线 | 日韩av一区二区在线观看 | 欧美一区二区在线观看 | 国产精品美女久久久久久免费 | 天天摸天天看 | 日韩免费视频一区二区 | 日韩在线视频免费观看 | 91精品久久久久久综合五月天 | 美女毛片免费看 |