---
GA: G-7BSJTG7RYN
---
通常用在[型別化名](https://hackmd.io/@elzuoc/rkcMxJJx3#%E5%9E%8B%E5%88%A5%E5%8C%96%E5%90%8D-Type-Alias)的時候,複合型別包含:
`union`:聯集型別
`intersection`:交集型別
首先,這裡所提到的 **聯集** 與 **交集** 的概念,與數學集合論所學到的概念不一樣,想了解可以先跳至 [比較數學集合與型別集合](https://hackmd.io/@elzuoc/rJRtRjUx3#%E6%AF%94%E8%BC%83%E6%95%B8%E5%AD%B8%E9%9B%86%E5%90%88%E8%88%87%E5%9E%8B%E5%88%A5%E9%9B%86%E5%90%88)。
### 聯集型別 Union Type
將型別進行聯集(`|`),來看個簡單的範例:
```typescript=
type Primitives = number | string | boolean | null | undefined;
```
這代表被註記為 `Primitives` 的變數,可以填入這 5 種型別值之一(`number`, `string`, `boolean`, `null`, `undefined`)。
我們再看一個範例:
```typescript=
type NullableSet = null & undefined;
```
這代表被註記為 `NullableSet` 的變數,可以填入這 2 種型別值之一(`null`, `undefined`)。
> **小知識:**
> 在 TypeScript 中,`null`, `undefined` 的聯集結果,稱為**Nullable Types**。
--
#### 互斥聯集 Discriminated Union
在複合型別中,這個方式較為常見。
假設我們有 `UserInfo1`, `UserInfo2` 兩個型別,同時我們建立一個 `UnionUserSet` 型別,它是 `UserInfo1`, `UserInfo2` 的聯集。
```typescript=
type UserInfo1 = {
name: string,
age: number,
};
type UserInfo2 = {
hasMobile: boolean,
isAdult: boolean,
};
type UnionUserSet = UserInfo1 | UserInfo2;
```
這代表被註記為 `UnionUserSet` 的變數,它的屬性可以是 `UserInfo1` 或 `UserInfo2` 存在的屬性。換個說法,它的屬性僅限於 `UserInfo1`, `UserInfo2` 中存在的屬性。

假設宣告一個變數 `setUnion` ,並且註記為 `UnionUserSet`,那麼它的屬性可以是 `name`, `age`, `hasMobile`, `isAdult` 的各種組合。像是:
```typescript=
const setUnion: UnionUserSet = {
name: 'string',
age: 18,
hasMobile: false,
};
```
若給了一個不存在於 `UserInfo1`, `UserInfo2` 的屬性,TypeScript 就會產生錯誤訊息。
```typescript=
const setUnion: UnionSet = {
name: 'string',
age: 18,
hasMobile: false,
isCheck: true, // Error
};
// Error: Object literal may only specify known properties, and 'isCheck' does not exist in type 'UnionSet'.
```
--
### 交集型別 Intersection Type
將型別進行交集(`&`),不過這個行為很少見,我們用剛剛的範例來看:
```typescript=
type UserInfo1 = {
name: string,
age: number,
};
type UserInfo2 = {
hasMobile: boolean,
isAdult: boolean,
};
type UnionUserSet = UserInfo1 & UserInfo2;
```
假設宣告一個變數 `setUnion` ,並且註記為 `UnionUserSet`,那麼它的屬性 **必須包含** `name`, `age`, `hasMobile`, `isAdult`,多一個少一個屬性都不行:
```typescript=
const setUnion: UnionSet = {
name: 'string',
age: 18,
hasMobile: false,
isAdult: true,
};
```
不過,若有選用屬性,則該屬性用不到時可省略。這個概念類似之後我們會提到的 [**介面擴展(Interface Extension)**](https://hackmd.io/@elzuoc/ryw1Am_xn#%E4%BB%8B%E9%9D%A2%E6%93%B4%E5%B1%95%EF%BC%88Interface-Extension--Interface-Inheritance%EF%BC%89)。
--
### 數學集合與型別集合的差異
**數學聯集** 與 **型別聯集**
> 數學聯集:兩個集合所有屬性都要
> 型別聯集:屬性只要存在於兩個集合之中即可
**數學交集** 與 **型別交集**
> 數學交集:只要兩個集合共同都有的屬性
> 型別交集:兩個集合所有屬性都要
直接看比較表:
| |數學|型別|
|---|---|---|
|聯集|兩個集合所有屬性都要|**屬性只要存在於兩個集合之中即可**|
|交集|只要兩個集合共同都有的屬性|**兩個集合所有屬性都要**|
--
### Type Guard (尚未有正式的中文譯名)
Type Guard 是一種行為的概稱,這個行為是「檢測某變數或表達式的型別」。
事實上,在 JavaScript 我們已經見過它,就是 `typeof` 關鍵字,而且不只它,包含 `Array.isArray()`, `Number.isNaN()`, `Number.isFinite()`, `setNull === null` 都是。
簡單來說,只要某個行為能夠 **正確**「檢測某變數或表達式的型別」,這個行為就稱為 Type Guard。
---
### Reference
- [讓TypeScript成為你全端開發的ACE!- Maxwell Huang](https://www.books.com.tw/products/0010859134)
- [讓 TypeScript 成為你全端開發的 ACE! 系列 - 第 11 屆 iThome 鐵人賽](https://ithelp.ithome.com.tw/users/20120614/ironman/2685)
- [TypeScript Official Site](https://www.typescriptlang.org/docs)
---
> 系列:[`跑完 JS30 就接著認識 TypeScript 入門`](https://hackmd.io/@elzuoc?tags=%5B%22%E8%B7%91%E5%AE%8C+JS30+%E5%B0%B1%E6%8E%A5%E8%91%97%E8%AA%8D%E8%AD%98+TypeScript+%E5%85%A5%E9%96%80%22%5D)
> 上一篇:[Day05:型別系統 - Never、Any、Unknown](https://hackmd.io/@elzuoc/Skd3Uree3)
> 下一篇:[Day07:型別系統 - 泛用型別 Generic Types](https://hackmd.io/@elzuoc/BJie-0Le3)
###### tags: [`跑完 JS30 就接著認識 TypeScript 入門`](https://hackmd.io/@elzuoc?tags=%5B%22%E8%B7%91%E5%AE%8C+JS30+%E5%B0%B1%E6%8E%A5%E8%91%97%E8%AA%8D%E8%AD%98+TypeScript+%E5%85%A5%E9%96%80%22%5D)
###### Created on ∥ March 21, 2023
###### 文章若有任何錯誤,還請不吝給予留言指正,謝謝大家!