欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

TypeScript中交叉類(lèi)型和聯(lián)合類(lèi)型的區(qū)別詳解

 更新時(shí)間:2023年09月25日 09:57:05   作者:前端小碼哥  
聯(lián)合類(lèi)型(Union Types)和交叉類(lèi)型(Intersection Types)是 TypeScript 中的兩種高級(jí)類(lèi)型,它們都用于組合多個(gè)類(lèi)型并生成新的類(lèi)型,但它們兩者之間的用法不一樣,本文小編就給大家講講TypeScript中交叉類(lèi)型和聯(lián)合類(lèi)型的區(qū)別,需要的朋友可以參考下

1. 定義

1.1. 聯(lián)合類(lèi)型(|)

在TS中,聯(lián)合類(lèi)型表示:一個(gè)值可以是多種類(lèi)型之一,使用邏輯“或”( | )運(yùn)算符來(lái)分隔多個(gè)類(lèi)型。

一個(gè)聯(lián)合類(lèi)型的變量,在使用時(shí)可以是多個(gè)類(lèi)型中的任意一種。

type UnionTypes = Type1 | Type2 | Type3;

1.2. 交叉類(lèi)型(&)

在TS中,交叉類(lèi)型表示:同時(shí)具備多種類(lèi)型的值,使用邏輯“與”( & )運(yùn)算符進(jìn)行組合。

一個(gè)交叉類(lèi)型的變量,將同時(shí)擁有多個(gè)類(lèi)型的屬性和方法。

type IntersectionTypes = Type1 & Type2 & Type3;

2. 聯(lián)合類(lèi)型

2.1. 基礎(chǔ)聯(lián)合類(lèi)型

當(dāng)一個(gè)變量可以是多種不同的類(lèi)型時(shí),可以使用聯(lián)合類(lèi)型來(lái)定義它。

例如,一個(gè)變量可以是 string 類(lèi)型或者 number 類(lèi)型。

let data: string | number;
data = 'hello ts';
data = 123;
data = false; // 編譯錯(cuò)誤:不能將類(lèi)型“boolean”分配給類(lèi)型“string | number”。ts(2322)

上面這段代碼中,我們定義了一個(gè)變量 data,類(lèi)型為 number 和 string 的聯(lián)合類(lèi)型,因此,data 的值只能是這兩種類(lèi)型中的其中一種,復(fù)制其它類(lèi)型的值會(huì)報(bào)錯(cuò)。

2.2. 對(duì)象聯(lián)合類(lèi)型

對(duì)象聯(lián)合類(lèi)型只能訪問(wèn)聯(lián)合中所有類(lèi)型共有的成員。

interface Admin {
  name: string;
  age: number;
}
interface User {
  name: string;
  sayHi(): void;
}
declare function Employee(): Admin | User;
let employee = Employee();
employee.name = 'Echo';
// 下面語(yǔ)句會(huì)報(bào)錯(cuò):age屬性不是 Admin 和 User 共有的屬性
employee.age = 26; // 編譯錯(cuò)誤:類(lèi)型“Admin | User”上不存在屬性“age”。類(lèi)型“User”上不存在屬性“age”。ts(2339)

上面這段代碼中,定義了兩個(gè)接口 Admin 和 User,接著使用 declare function 聲明了一個(gè) Employee 函數(shù),該函數(shù)的返回類(lèi)型為 Admin 或 User。之后通過(guò)調(diào)用 Employee 函數(shù)并將返回值賦給了 employee 變量。接著將 employee 對(duì)象中 name 屬性的值設(shè)置為 'Echo' 是可以的,因?yàn)?name 屬性是 Admin 和 User 共有的屬性。而將 employee 對(duì)象中 age 屬性的值設(shè)置為 26 時(shí)會(huì)出現(xiàn)編譯錯(cuò)誤,錯(cuò)誤信息指出類(lèi)型 Admin | User 上不存在屬性 age。這是因?yàn)?age 屬性只存在于 Admin 接口中,而不屬于 User 接口。

造成該錯(cuò)誤的原因是,TypeScript 在聯(lián)合類(lèi)型上只能訪問(wèn)聯(lián)合類(lèi)型中所有類(lèi)型的共有屬性和方法。 因此,通過(guò)聯(lián)合類(lèi)型的變量只能訪問(wèn) name 屬性,而不能訪問(wèn) age 屬性。

2.3. 字面量聯(lián)合類(lèi)型

聯(lián)合類(lèi)型可以與字面量類(lèi)型一起使用,用于限定一個(gè)值只能是某幾個(gè)特定的值之一。

let direction: "Up" | "Right" | "Down" | "Left";
direction = "Right";
direction = "none"; // 編譯錯(cuò)誤,只能取值為 "Up" | "Right" | "Down" | "Left"

3. 交叉類(lèi)型

在 TypeScript 中,交叉類(lèi)型(Intersection Types)允許我們將多個(gè)類(lèi)型合并為一個(gè)新的類(lèi)型。

使用交叉類(lèi)型可以將多個(gè)對(duì)象的屬性和方法合并到一個(gè)新的對(duì)象中。

type Person = {
  name: string;
}
type User = {
  age: number;
}
let person: Person & User;
person = {
  name: 'Echo',
  age: 26,
}
// 編譯錯(cuò)誤:
// 不能將類(lèi)型“{ name: string; }”分配給類(lèi)型“Person & User”。
// 類(lèi)型 "{ name: string; }" 中缺少屬性 "age",但類(lèi)型 "User" 中需要該屬性。ts(2322)
// index.ts(7, 3): 在此處聲明了 "age"。
person = {
  name: 'Steven',
}

上面這段代碼中,我們定義了 Person 和 User 兩個(gè)類(lèi)型,然后,我們定義一個(gè)變量 person,它的類(lèi)型是使用交叉類(lèi)型 Person & User 來(lái)創(chuàng)建的一個(gè)新類(lèi)型,那么,此時(shí)變量 person 就同時(shí)具備了 name 和 age 屬性。

3.1. 交叉類(lèi)型的成員類(lèi)型是基礎(chǔ)類(lèi)型

交叉類(lèi)型的成員類(lèi)型可以為任意類(lèi)型,但需要注意的是,如果交叉類(lèi)型的成員類(lèi)型是基礎(chǔ)類(lèi)型時(shí),交叉類(lèi)型的結(jié)果是 never。

type T1 = string & number;   // 等同于 type T1 = never
type T2 = number & boolean;  // 等同于 type T2 = never

3.2. 交叉類(lèi)型的成員類(lèi)型是對(duì)象類(lèi)型

當(dāng)交叉類(lèi)型的成員類(lèi)型為對(duì)象類(lèi)型時(shí),結(jié)果類(lèi)型又會(huì)是什么?

下面我們看一個(gè)簡(jiǎn)單的例子:

type TypeA = {
  x: number;
  y: number;
}
type TypeB = {
  y: number;
  z: number;
}
type TypeC = {
  z: number;
}

上面這段代碼中,我們定義了三個(gè)類(lèi)型:TypeA、TypeB 和 TypeC,分別表示類(lèi)型 A、B 和 C,類(lèi)型 A 具有屬性成員 x 和 y,類(lèi)型 B 具有屬性成員 y 和 z,類(lèi)型 C 具有屬性成員 z,每個(gè)類(lèi)型具有不同的屬性成員。

type MergedType = TypeA & TypeB & TypeC;

上面這段代碼中,我們使用交叉類(lèi)型 TypeA & TypeB & TypeC 創(chuàng)建了一個(gè)新的類(lèi)型 MergedType,它包含了類(lèi)型 A、B 和 C 的屬性成員,那么,合并后的交叉類(lèi)型的成員類(lèi)型為:屬性成員 x 的類(lèi)型是 A 的類(lèi)型,屬性成員 y 的類(lèi)型是 A 和 B 的交叉類(lèi)型,屬性成員 z 的類(lèi)型是 B 和 C 的交叉類(lèi)型。

let t: MergedType;
const t1 = {
  x: 1,
  y: 2,
  z: 3,
}
const t2 = {
  x: 10,
  y: 20,
}
t = t1;
// 編譯錯(cuò)誤:
// 不能將類(lèi)型“{ x: number; y: number; }”分配給類(lèi)型“MergedType”。
// 類(lèi)型 "{ x: number; y: number; }" 中缺少屬性 "z",但類(lèi)型 "TypeB" 中需要該屬性。ts(2322)
// index.ts(10, 3): 在此處聲明了 "z"。
t = t2;

上面這段代碼中,定義了一個(gè)變量 t,它的類(lèi)型是 TypeA & TypeB & TypeC 組成的交叉類(lèi)型,然后再定義了兩個(gè)變量 t1 和 t2,t1 同時(shí)滿足 TypeA、TypeB 和 TypeC 類(lèi)型約束,因此能賦值給交叉類(lèi)型 t。而 t2 滿足 TypeA 類(lèi)型約束,是 TypeA 類(lèi)型,但并不能賦值給交叉類(lèi)型 t,當(dāng) t2 賦值給 t 的時(shí)候,編譯器會(huì)報(bào)錯(cuò)。

由此可見(jiàn):交叉類(lèi)型的類(lèi)型成員由各個(gè)類(lèi)型成員的屬性成員的并集組成,并且這些屬性成員的類(lèi)型是各個(gè)成員類(lèi)型的交叉類(lèi)型。這種規(guī)則使得交叉類(lèi)型能夠?qū)⒍鄠€(gè)類(lèi)型的屬性成員合并到一個(gè)類(lèi)型中,并且可以同時(shí)訪問(wèn)這些屬性成員。

3.3. 成員類(lèi)型合并

如果交叉類(lèi)型的成員類(lèi)型中有相同的類(lèi)型,合并后的交叉類(lèi)型將只保留一份該成員的類(lèi)型。

type T1 = string & string;   // 等同于 type T1 = string
type T2 = string & string & string;  // 等同于 type T2 = string

上面這段代碼中,類(lèi)型 T1 由兩個(gè) string 構(gòu)成,由于成員類(lèi)型相同,所以合并成為一個(gè) string。類(lèi)型 T2 由三個(gè) string 構(gòu)成,由于成員類(lèi)型相同,所以合并成為一個(gè) string。

3.4. 交叉類(lèi)型的索引簽名

當(dāng)交叉類(lèi)型的成員類(lèi)型之一具有數(shù)字索引簽名(即可通過(guò)數(shù)字索引訪問(wèn))或字符串索引簽名(即可通過(guò)字符串索引訪問(wèn))時(shí),結(jié)果類(lèi)型也將包含相應(yīng)的數(shù)字索引簽名或字符串索引簽名。

結(jié)果類(lèi)型的索引簽名值類(lèi)型是各個(gè)成員類(lèi)型索引簽名值類(lèi)型的交叉類(lèi)型。也就是說(shuō),通過(guò)交叉類(lèi)型合并的結(jié)果類(lèi)型的索引簽名值類(lèi)型將是各個(gè)成員類(lèi)型索引簽名值類(lèi)型的交叉類(lèi)型。

type TypeA = {
  [key: string]: string;
};
type TypeB = {
  [key: number]: string;
};
type MergedType = TypeA & TypeB;
const mergedObject: MergedType = {
  name: 'Echo',
  gender: 'Male',
  city: 'Guang Zhou',
  1: 'abcd',
};
console.log(mergedObject['name']);   // 輸出:Echo
console.log(mergedObject['gender']); // 輸出:Male
console.log(mergedObject['city']);   // 輸出:Guang Zhou
console.log(mergedObject[1]);        // 輸出:abcd

上面這段代碼中,定義了兩個(gè)類(lèi)型 TypeA 和 TypeB,其中,TypeA 具有字符串索引簽名,TypeB 具有數(shù)字索引簽名,也就是說(shuō),TypeA 允許使用字符串作為索引,而 TypeB 允許使用數(shù)字作為索引。然后,使用交叉類(lèi)型 TypeA & TypeB 創(chuàng)建了一個(gè)新的類(lèi)型 MergedType,它包含了 TypeA 和 TypeB 的索引簽名。接著,我們創(chuàng)建了一個(gè)名為 mergedObject 的對(duì)象,它的類(lèi)型指定為交叉類(lèi)型 MergedType,該對(duì)象可以通過(guò)數(shù)字索引或字符串索引來(lái)訪問(wèn),并給這些索引賦予了相應(yīng)的值。最后,我們通過(guò)索引訪問(wèn) mergedObject 對(duì)象的值來(lái)驗(yàn)證交叉類(lèi)型的索引簽名的合并情況。

3.5. 交叉類(lèi)型的調(diào)用簽名

當(dāng)交叉類(lèi)型的成員類(lèi)型中至少有一個(gè)具有調(diào)用簽名時(shí),交叉類(lèi)型的結(jié)果類(lèi)型也會(huì)包含這個(gè)調(diào)用簽名。

換句話說(shuō),交叉類(lèi)型中至少一個(gè)成員的調(diào)用簽名會(huì)被合并到結(jié)果類(lèi)型中。

此外,如果交叉類(lèi)型的多個(gè)成員類(lèi)型都有調(diào)用簽名,那么結(jié)果類(lèi)型將會(huì)形成調(diào)用簽名重載的結(jié)構(gòu)。調(diào)用簽名重載允許我們?yōu)橥粋€(gè)函數(shù)提供多個(gè)不同的調(diào)用方式,具體取決于參數(shù)類(lèi)型和返回值類(lèi)型。

可以將交叉類(lèi)型的成員類(lèi)型的調(diào)用簽名視為函數(shù)的簽名,交叉類(lèi)型的結(jié)果類(lèi)型即為這些簽名的合并。

type FunctionA = (x: number, y: number) => number;
type FunctionB = (x: string, y: string) => string;
type FunctionType = FunctionA & FunctionB;
const option: FunctionType = (x, y) => x + y;
console.log(option(10, 20));     // 輸出: 30
console.log(option('a', 'b'));   // 輸出: ab

上面這段代碼中,定義了兩個(gè)類(lèi)型 FunctionA 和 FunctionB,它們接收 x 和 y 兩個(gè)參數(shù),其中,F(xiàn)unctionA 兩個(gè)參數(shù)的類(lèi)型和函數(shù)返回值的類(lèi)型都是 number 類(lèi)型,F(xiàn)unctionB 兩個(gè)參數(shù)的類(lèi)型和函數(shù)返回值的類(lèi)型都是 string 類(lèi)型。然后,使用交叉類(lèi)型 FunctionA & FunctionB 創(chuàng)建了一個(gè)新的類(lèi)型 FunctionType,這個(gè)交叉類(lèi)型包含了兩個(gè)成員類(lèi)型的調(diào)用簽名。最后,我們創(chuàng)建了一個(gè)名為 option 的變量,它的類(lèi)型被定義為 FunctionType,也就是 FunctionA 和 FunctionB 的交叉類(lèi)型。我們可以使用 option 等同于調(diào)用兩個(gè)函數(shù)的方式來(lái)執(zhí)行相應(yīng)的運(yùn)算,option(10, 20) 相當(dāng)于加法運(yùn)算,輸出結(jié)果為:30,option('a', 'b') 相當(dāng)于字符串的拼接,輸出結(jié)果為:ab。

3.6. 交叉類(lèi)型的構(gòu)造簽名

當(dāng)交叉類(lèi)型的成員類(lèi)型中至少有一個(gè)具有構(gòu)造簽名時(shí),交叉類(lèi)型的結(jié)果類(lèi)型也會(huì)包含這個(gè)構(gòu)造簽名。

換句話說(shuō),交叉類(lèi)型中至少存在一個(gè)成員的構(gòu)造簽名會(huì)被合并到結(jié)果類(lèi)型中。

如果交叉類(lèi)型的多個(gè)成員類(lèi)型都具有構(gòu)造簽名,那么結(jié)果類(lèi)型將形成構(gòu)造簽名重載的結(jié)構(gòu)。構(gòu)造簽名重載允許我們?yōu)橥粋€(gè)類(lèi)提供多個(gè)不同的構(gòu)造方式,具體取決于參數(shù)列表。

interface Foo {
  new (name: string): string
}
interface Bar {
  new (name: number): number;
}
type FooBar = Foo & Bar;
declare const T: FooBar;
const instance1 = new T('Echo');
const instance2 = new T(26);

上面這段代碼中,我們定義了兩個(gè)接口 Foo 和 Bar,它們都具有構(gòu)造簽名,分別接受不同的參數(shù)類(lèi)型并返回對(duì)應(yīng)的類(lèi)型。接著,我們使用交叉類(lèi)型 Foo & Bar 創(chuàng)建了一個(gè)新的類(lèi)型 FooBar,它是 Foo 和 Bar 的交叉類(lèi)型,意味著 FooBar 同時(shí)具備了 Foo 和 Bar 接口的構(gòu)造簽名。然后,通過(guò) declare 關(guān)鍵字聲明了一個(gè)常量 T,它的類(lèi)型被定義為 FooBar。接著我們創(chuàng)建了兩個(gè)實(shí)例 instance1 和 instance2。由于 T 的類(lèi)型為 FooBar,我們可以使用 new T 的語(yǔ)法來(lái)實(shí)例化對(duì)象。對(duì)于 instance1,使用字符串 'Echo' 作為參數(shù)傳遞給構(gòu)造函數(shù),這符合 Foo 接口中定義的構(gòu)造簽名,所以實(shí)例化成功,返回一個(gè)字符串類(lèi)型的實(shí)例。對(duì)于 instance2,使用數(shù)字 26 作為參數(shù)傳遞給構(gòu)造函數(shù),這符合 Bar 接口中定義的構(gòu)造簽名,所以實(shí)例化成功,返回一個(gè)數(shù)字類(lèi)型的實(shí)例。

4. 總結(jié)

  • 聯(lián)合類(lèi)型只能訪問(wèn)共有的屬性和方法。例如,如果一個(gè)變量是 number 類(lèi)型或者 string 類(lèi)型,那么只能使用這兩種類(lèi)型共有的屬性和方法。
  • 聯(lián)合類(lèi)型中的變量,如果在特定條件下可以判斷出其具體的類(lèi)型,可以使用類(lèi)型斷言(as語(yǔ)法)來(lái)告訴編譯器具體的類(lèi)型。
  • 交叉類(lèi)型的結(jié)果包含了所有成員類(lèi)型的屬性和方法,通過(guò)合并同名成員實(shí)現(xiàn)。屬性會(huì)合并為并集類(lèi)型,方法會(huì)合并為聯(lián)合類(lèi)型。
  • 當(dāng)成員類(lèi)型具有調(diào)用簽名或構(gòu)造簽名時(shí),交叉類(lèi)型的結(jié)果將形成相應(yīng)簽名的重載。

以上就是TypeScript中交叉類(lèi)型和聯(lián)合類(lèi)型的區(qū)別詳解的詳細(xì)內(nèi)容,更多關(guān)于TypeScript交叉類(lèi)型和聯(lián)合類(lèi)型區(qū)別的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論