偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

快速理解 TypeScript 的逆變和協(xié)變

開發(fā) 前端
TypeScript 給 JavaScript 添加了一套靜態(tài)類型系統(tǒng),是為了保證類型安全的,也就是保證變量只能賦同類型的值,對象只能訪問它有的屬性、方法。

深入學習 TypeScript 類型系統(tǒng)的話,逆變、協(xié)變、雙向協(xié)變、不變是繞不過去的概念。

這些概念看起來挺高大上的,其實并不復(fù)雜,這篇文章我們就來學習下它們吧。

類型安全和型變

TypeScript 給 JavaScript 添加了一套靜態(tài)類型系統(tǒng),是為了保證類型安全的,也就是保證變量只能賦同類型的值,對象只能訪問它有的屬性、方法。

比如 number 類型的值不能賦值給 boolean 類型的變量,Date 類型的對象就不能調(diào)用 exec 方法。

這是類型檢查做的事情,遇到類型安全問題會在編譯時報錯。

但是這種類型安全的限制也不能太死板,有的時候需要一些變通,比如子類型是可以賦值給父類型的變量的,可以完全當成父類型來使用,也就是“型變”(類型改變)。

這種“型變”分為兩種,一種是子類型可以賦值給父類型,叫做協(xié)變,一種是父類型可以賦值給子類型,叫做逆變。

先來看下協(xié)變:

協(xié)變

其中協(xié)變是很好理解的,比如我們有兩個 interface:

interface Person {
name: string;
age: number;
}
interface Guang {
name: string;
age: number;
hobbies: string[]
}

這里 Guang 是 Person 的子類型,更具體,那么 Guang 類型的變量就可以賦值給 Person 類型:

這并不會報錯,雖然這倆類型不一樣,但是依然是類型安全的。

這種子類型可以賦值給父類型的情況就叫做協(xié)變。

為什么要支持協(xié)變很容易理解:類型系統(tǒng)支持了父子類型,那如果子類型還不能賦值給父類型,還叫父子類型么?

所以型變是實現(xiàn)類型父子關(guān)系必須的,它在保證類型安全的基礎(chǔ)上,增加了類型系統(tǒng)的靈活性。

逆變相對難理解一些:

逆變

我們有這樣兩個函數(shù):

let printHobbies: (guang: Guang) => void;
printHobbies = (guang) => {
console.log(guang.hobbies);
}
let printName: (person: Person) => void;
printName = (person) => {
console.log(person.name);
}

printHobbies 的參數(shù)是 printName 參數(shù)的子類型。

那么問題來了,printName 能賦值給 printHobbies 么?printHobbies 能賦值給 printName 么?

測試一下發(fā)現(xiàn)是這樣的:

printName 的參數(shù)不是 printHobbies 的父類型么,為啥能賦值給子類型?

因為這個函數(shù)調(diào)用的時候是按照 Guang 來約束的類型,但實際上函數(shù)只用到了父類型 Person 的屬性和方法,當然不會有問題,依然是類型安全的。

這就是逆變,函數(shù)的參數(shù)有逆變的性質(zhì)(而返回值是協(xié)變的,也就是子類型可以賦值給父類型)。

那反過來呢,如果 printHoobies 賦值給 printName 會發(fā)生什么?

因為函數(shù)聲明的時候是按照 Person 來約束類型,但是調(diào)用的時候是按照 Guang 的類型來訪問的屬性和方法,那自然類型不安全了,所以就會報錯。

但是在 ts2.x 之前支持這種賦值,也就是父類型可以賦值給子類型,子類型可以賦值給父類型,既逆變又協(xié)變,叫做“雙向協(xié)變”。

但是這明顯是有問題的,不能保證類型安全,所以之后 ts 加了一個編譯選項 strictFunctionTypes,設(shè)置為 true 就只支持函數(shù)參數(shù)的逆變,設(shè)置為 false 則是雙向協(xié)變。

我們把 strictFunctionTypes 關(guān)掉之后,就會發(fā)現(xiàn)兩種賦值都可以了:

這樣就支持函數(shù)參數(shù)的雙向協(xié)變,類型檢查不會報錯,但不能嚴格保證類型安全。

開啟之后,函數(shù)參數(shù)就只支持逆變,子類型賦值給父類型就會報錯:

在類型編程中這種逆變性質(zhì)有什么用呢?

還記得之前聯(lián)合轉(zhuǎn)交叉的實現(xiàn)么?

type UnionToIntersection<U> = 
(U extends U ? (x: U) => unknown : never) extends (x: infer R) => unknown
? R
: never

類型參數(shù) U 是要轉(zhuǎn)換的聯(lián)合類型。

U extends U 是為了觸發(fā)聯(lián)合類型的 distributive 的性質(zhì),讓每個類型單獨傳入做計算,最后合并。

利用 U 做為參數(shù)構(gòu)造個函數(shù),通過模式匹配取參數(shù)的類型。

結(jié)果就是交叉類型:

我們通過構(gòu)造了多個函數(shù)類型,然后模式提取參數(shù)類型的方式,來實現(xiàn)了聯(lián)合轉(zhuǎn)交叉,這里就是因為函數(shù)參數(shù)是逆變的,會返回聯(lián)合類型的幾個類型的子類型,也就是更具體的交叉類型。

逆變和協(xié)變都是型變,是針對父子類型而言的,非父子類型自然就不會型變,也就是不變:

不變

非父子類型之間不會發(fā)生型變,只要類型不一樣就會報錯:

那類型之間的父子關(guān)系是怎么確定的呢,好像也沒有看到 extends 的繼承?

類型父子關(guān)系的判斷

像 java 里面的類型都是通過 extends 繼承的,如果 A extends B,那 A 就是 B 的子類型。這種叫做名義類型系統(tǒng)(nominal type)。

而 ts 里不看這個,只要結(jié)構(gòu)上是一致的,那么就可以確定父子關(guān)系,這種叫做結(jié)構(gòu)類型系統(tǒng)(structual type)。

還是拿上面那個例子來說:

Guang 和 Person 有 extends 的關(guān)系么?

沒有呀。

那是怎么確定父子關(guān)系的?

通過結(jié)構(gòu),更具體的那個是子類型。這里的 Guang 有 Person 的所有屬性,并且還多了一些屬性,所以 Guang 是 Person 的子類型。

注意,這里用的是更具體,而不是更多。

判斷聯(lián)合類型父子關(guān)系的時候, 'a' | 'b' 和 'a' | 'b' | 'c' 哪個更具體?

'a' | 'b' 更具體,所以 'a' | 'b' 是 'a' | 'b' | 'c' 的子類型。

測試下:

總結(jié)

ts 通過給 js 添加了靜態(tài)類型系統(tǒng)來保證了類型安全,大多數(shù)情況下不同類型之間是不能賦值的,但是為了增加類型系統(tǒng)靈活性,設(shè)計了父子類型的概念。父子類型之間自然應(yīng)該能賦值,也就是會發(fā)生型變。

型變分為逆變和協(xié)變。協(xié)變很容易理解,就是子類型賦值給父類型。逆變主要是函數(shù)賦值的時候函數(shù)參數(shù)的性質(zhì),參數(shù)的父類型可以賦值給子類型,這是因為按照子類型來聲明的參數(shù),訪問父類型的屬性和方法自然沒問題,依然是類型安全的。但反過來就不一定了。

不過 ts 2.x 之前反過來依然是可以賦值的,也就是既逆變又協(xié)變,叫做雙向協(xié)變。

為了更嚴格的保證類型安全,ts 添加了 strictFunctionTypes 的編譯選項,開啟以后函數(shù)參數(shù)就只支持逆變,否則支持雙向協(xié)變。

型變都是針對父子類型來說的,非父子類型自然就不會型變也就是不變。

ts 中父子類型的判定是按照結(jié)構(gòu)來看的,更具體的那個是子類型。

理解了如何判斷父子類型(結(jié)構(gòu)類型系統(tǒng)),父子類型的型變(逆變、協(xié)變、雙向協(xié)變),很多類型兼容問題就能得到解釋了。

責任編輯:姜華 來源: 神光的編程秘籍
相關(guān)推薦

2020-09-29 06:37:30

Java泛型

2009-08-03 18:24:28

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

2009-05-27 11:30:20

C#Visual Stud協(xié)變

2020-08-03 08:13:51

Vue3TypeScript

2011-01-14 10:27:18

C#.netasp.net

2012-03-13 09:32:15

C#協(xié)變

2013-10-31 09:36:43

程序員程序高手

2010-08-17 11:18:19

BISAP商業(yè)智能

2010-01-20 09:17:46

2015-02-06 17:00:04

2018-04-27 16:45:41

華為

2018-08-01 15:48:05

搜狗

2023-01-29 09:15:42

2011-11-18 10:00:05

云計算IT管理

2011-11-17 17:22:10

IT管理云計算

2015-09-11 10:45:55

服務(wù)器華為

2020-12-25 16:52:28

CIO數(shù)字化轉(zhuǎn)型計世

2009-07-07 11:04:12

百變?nèi)湎x病毒卡巴斯基
點贊
收藏

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