---
# System prepended metadata

title: Typescript 型別與介面
tags: [Typescript]

---

# Typescript 型別與介面

###### tags: `Typescript`

## 壹、前線維護・型別推論 X 註記 - Type Inference & Annotation

### 一、 基礎型別（Types）
![](https://i.imgur.com/qsxPANb.png)

- **原始型別 Primitive Types**
包含 **number**, **string**, **boolean**, **undefined**, **null**, ES6 介紹的 **symbol** 與時常會在函式型別裡看到的 **void**

- **物件型別 Object Types**
但我個人還會再細分成小類別，但這些型別的共同特徵是 —— 從原始型別或物件型別組合出來的複合型態（比如物件裡面的 Key-Value 個別是 string 和 number 型別組合成的）：
    - 基礎物件型別：包含 JSON 物件，陣列（Array<T>或T[]），類別以及類別產出的物件（也就是 Class 以及藉由 Class new 出來的 Instance）
    - TypeScript 擴充型別：即 Enum 與 Tuple，內建在 TypeScript
    - 函式型別 Function Types：類似於 (input) => (Ouput) 這種格式的型別，後面會再多做說明
- **明文型別 Literal Type**
一個值本身也可以成為一個型別，比如字串 "Hello world" —— 若成為某變數的型別的話，它只能存剛好等於"Hello world"` 字串值；但通常會看到的是 Object Literal Type，後面也會再多做說明
- **特殊型別**
筆者自行分類的型別，即 any、never（TS 2.0釋出）以及最新的 unknown 型別（TS 3.0釋出），讀者可能覺得莫名其妙，不過這些型別的存在仍然有它的意義，而且很重要，陷阱總是出現在不理解這些特殊型別的特性
- **複合型別**
筆者自行分類的型別，即 union 與 intersection 的型別組合，但是跟其他的型別的差別在於：這類型的型別都是由邏輯運算子組成，分別為 | 與 &
- **通用型別**
Generic Types：留待進階的 TypeScript 文章介紹，一種讓程式碼可以變得更加通用的絕招


### 二、型別推論在原始型的運作

#### 1.型別推論
- TS 除了認得定義過後的變數外，也認得該變數型別是 Boolean，這個辨識推論型別的行為就是所謂的**型別推論**（Type Inference）
![](https://i.imgur.com/vCieknt.png)
#### 2.Nullable Types
- 但如果對 nothing 或 nothingLiterally 這兩個型別作確認的話，結果 TypeScript 會把它們推論成 any 型別，因為 null 或 undefined 被稱為 **Nullable Types**，被認為是 any 型別
![](https://i.imgur.com/rIRg04U.png)

- Nullable Types 會被認為是 any 型別，因此可以被指定為任何型態
![](https://i.imgur.com/2ll0HA3.png)

#### 3.  TDZ （Temporal Dead Zone，暫時性死區）
- 宣告一個變數後，在還沒指派值之前，用另外一個變數去接他，這時 TS 就會提出質疑。
![](https://i.imgur.com/XIiIk7S.png)
- 在未確定變數被正式丟入合法的值之前的這段空間，不能使用該變數。
![](https://i.imgur.com/igX7Xnd.png)

#### 4. 對遲滯性指派進行型別註記
```javascript=
let A: type;

A = B as type;
```
    
    
## 貳、物件型別 X 完整性理論 - Object Types Basics
    
![](https://i.imgur.com/08H3R5u.png)
    
### 一、基礎物件型別
#### 1. **JSON 物件格式**
    
TS 會提醒你推論後的型別是什麼
    
![](https://i.imgur.com/3r149DA.png)
    
就算是 nullable 和 undefine 的型別也會出來，而不是 any
    
![](https://i.imgur.com/xrl21Bq.png)
    
#### 2. 型別覆蓋的例子
```javascript=
let info = {
  name: 'Maxwell',
  age: 20,
  hasPet: false,
}

let something = {
  null: null,
  define: undefined,
}
```
- **屬性值被錯誤的型別插入/覆寫干擾**
型別錯誤，TS 會主動給予提示
![](https://i.imgur.com/DOhVlcH.png)

- **物件分別被正確或者是錯誤的物件格式整體複寫**
多一個鍵或少一個鍵都不行
![](https://i.imgur.com/zCrOQEE.png)
    
- 型別推導時就會把整個物件，包括 key-value 的型別都作定義
![](https://i.imgur.com/NEWX9mj.png)
    
- 主動註記物件型別時，會被標記為物件型別，因此只要是物件型別就可以付與值給它
![](https://i.imgur.com/IsrNrna.png)

- **直接對物件新增值**
新增或減少值會引起 TS 的警告
![](https://i.imgur.com/rRlCR0A.png)
    
- 結論
    - 對物件內的屬性覆寫，其值的型別必須相等
    - 對整個物件覆寫，格式必須完全相等

- 用以下三種形式新增物件是允許的
```javascript=
let nestedObject = {
  prop: 'Hello',
  child: {
    prop1: 12,
    prop2: false,
  }
}

    
let obj1 = {hello: 'world'}
let obj2 = {...obj1, goodbye: 'Cruel world'}


let obj3 = {hello: 'Another World'}
let obj4 = Object.assign(obj3, {
  goodbye: 'Cruel World'
})
```

### 二. 定義物件
let justAnObject1 = { hello: 'World' }
let justAnObject2: object = { hello: 'World' } 

定義物件的時候這兩種寫法，
1. **沒有主動註記物件型別**，第一個可以改寫裡面的hello的值 justAnObject1.hello = ‘WW’
2. **主動註記物件型別**，第二個則是要**整個物件覆蓋掉**，然後連key值都可以改 = justAnObject = { goodbye: 'Cruel world', kk: 'Another'}
因為 TS 認為object 型別指的是任何 JS 物件（儘管格式不同）都可以被套入，但是不允許對該物件做細部微調
    
- 物件狹義的定義
    典型的 {} 這種東西的寫法
- 物件廣義物件的定義
包含 JSON 格式的物件、陣列、函式、類別、類別創建出之物件
    
#### 1. 將狹義物件用廣義物件覆蓋
實驗證實，在物件主動標記型別的狀態下，廣義定義的物件是可以覆蓋的
![](https://i.imgur.com/GXu6Kur.png)

#### 2. 將廣義物件用狹義物件覆蓋
    
![](https://i.imgur.com/tksmPKw.png)
    
**廣義物件在被 TypeScript 推論的狀態下，屬性不能被任意新增或更改成其他型別**
能夠做的事情只有：

- 全面覆寫，廣義物件的屬性對照型別格式也要完全對位
- 更改廣義物件本身就擁有屬性對應的值，其中：要帶入的值的型態必須對應到該屬性的型態


## 參、函式型別 X 積極註記 - Function Types
    
![](https://i.imgur.com/jmqUjoh.png)

### 1. 函式註記- 函數參數
    函數參數如果不標記爲何種型別，他只能是 any，如果 TS 不管輸入參數的型別。像下面的函式就會變成字串型別＋數字型別
```javascript=
let addition = function(paras1, paras2) {
    return paras1 + paras2
}

addition(1, '2')
```
因此必須在函數的參數上加上型別
```javascript=
let addition = function(paras1: number, paras2: number) {
    return paras1 + paras2
}

addition(1, 2)
```

### 1. 函式註記-函式輸出的註記
    
在輸入型別確認後，TS 會自動幫我們推導出輸出型別為何
![](https://i.imgur.com/TUlWQNx.png)

也可以自行註記型別
![](https://i.imgur.com/G3C6FNH.png)
    

- 如果輸出的型別為 any 該如何註記?
![](https://i.imgur.com/H8JjSDt.png)

- 我們儘量不要讓變數被推導為 any 的型態。
![](https://i.imgur.com/lNcZAEx.png)

- 函式不回傳值的狀態 void
![](https://i.imgur.com/SH8dtqO.png)
    
- 驗證小實驗
    - 只有定義回傳為 undefine 時，卻沒回傳值，TS檢查不會通過
![](https://i.imgur.com/U3ktTPK.png)


## 肆、陣列型別 X 型別陣列 - Array Types
![](https://i.imgur.com/u1M6H7u.png)

### 1.陣列型別 Array Types
- 單一陣列型別
TypeScript 會按照開發者認為的邏輯，把這種元素（Element）皆為同型別 T 的陣列用 T[] 的方式表示。
![](https://i.imgur.com/WAQ0KMO.png)

- 混合陣列型別
![](https://i.imgur.com/gnhsyO5.png)
    
- 函式陣列型別
![](https://i.imgur.com/YDi8aVj.png)

- 一個陣列中擁有不同種類的型別
![](https://i.imgur.com/Xp5dLtJ.png)
![](https://i.imgur.com/uEzHhkA.png)

- 陣列中物件擁有不一致數量的屬性
![](https://i.imgur.com/ALjFEuZ.png)

### 2. 定義變數的型別
如果要在陣列中加上一個 null，就得再定義陣列時使用 union 允許 null
![](https://i.imgur.com/TZsoBow.png)
    
## 肆、前線維護・陣列與函式 X 陣列與元組 - Array & Functions & Tuples
![](https://i.imgur.com/ZaiYaLN.png)

    
### 一、回呼函數
回呼函數一般情況下 TS 會幫你註記
![](https://i.imgur.com/tugbCar.png)
    
### 二、陣列與元組 Arrays & Tuples
- 相對於型別註記(string|Date)[]，我們只知道陣列中有這兩個型別，但不能指定哪個位置必須放哪個型別。
因此 TS 用元組來做註記
![](https://i.imgur.com/tVkF4Vd.png)

- 運用型別化名註記元組型別
![](https://i.imgur.com/faTj4yf.png)

- 元組與陣列表示法
![](https://i.imgur.com/6tTv0fV.png)

- 不過元組的缺點就是：型別等同的兩個元素，儘管型別上是正確的，但是資料的意義上是不同的，就算被顛倒，TypeScript 也因為只會比對型別而不會進行警告
    ![](https://i.imgur.com/MmDUG4u.png)
通常會建議資料儘量用 JSON 物件格式表示
    ![](https://i.imgur.com/4Au3XwN.png)


## 伍、前線維護・列舉型別 X 主觀列舉 - Enumerated Types
![](https://i.imgur.com/YixmmhK.png)

### 一、列舉(Enumerate)
把變數的範圍限制在某些限制下進行存取並賦予其定義
- 一串東西的集合
- 同時具備**主觀上強烈的共通性(Similarity)**及**獨有特質(Uniqueness)**    
Ex: 星期幾、上下左右、交通工具...

- 定義列舉時不需等號
```typescript=
enum WeekDay {
  Sunday,
  Monday,
  Tuesday,
  Wednesday,
  Thursday,
  Friday,
  Saturday
}
```
    
- ts 將上面這段程式碼編譯的結果
```javascript=
var WeekDay;
(function (WeekDay) {
    WeekDay["Sunday"] = "Sun";
    WeekDay["Monday"] = "Mon";
    WeekDay["Tuesday"] = "Tue";
    WeekDay["Wednesday"] = "Wed";
    WeekDay["Thursday"] = "Thu";
    WeekDay["Friday"] = "Fri";
    WeekDay["Saturday"] = "Sat";
})(WeekDay || (WeekDay = {}));
```

- 取用 WeekDay 的值會是 Enum -> 
```typescript=
let TGIF = WeekDay.Sunday
console.log(TGIF)
// TGIF 為 enum

let Sunday = WeekDay[TGIF]
console.log(Sunday);
// Sunday 為 string 型別
```
    
- 指向字串用法
```typescript=
enum Week {
  Sunday = "Sun",
  Monday = "Mon",
  Tuesday = "Tue",
  Wednesday = "Wed",
  Thursday = "Thu",
  Friday = "Fri",
  Saturday = "Sat"
}
    
// 編譯結果 ===>
var Week;
(function (Week) {
    Week["Sunday"] = "Sun";
    Week["Monday"] = "Mon";
    Week["Tuesday"] = "Tue";
    Week["Wednesday"] = "Wed";
    Week["Thursday"] = "Thu";
    Week["Friday"] = "Fri";
    Week["Saturday"] = "Sat";
})(Week || (Week = {}));
```
- 指向數字，自動遞增
```typescript=
enum JobGrade{
  JuniorE8 = 8,
  JuniorE9,
  SeniorE10,
  SeniorE11,
  Other = 0,
  Guest
}
    
// 編譯結果 ===>
var JobGrade;
(function (JobGrade) {
    JobGrade[JobGrade["JuniorE8"] = 8] = "JuniorE8";
    JobGrade[JobGrade["JuniorE9"] = 9] = "JuniorE9";
    JobGrade[JobGrade["SeniorE10"] = 10] = "SeniorE10";
    JobGrade[JobGrade["SeniorE11"] = 11] = "SeniorE11";
    JobGrade[JobGrade["Other"] = 0] = "Other";
    JobGrade[JobGrade["Guest"] = 1] = "Guest";
})(JobGrade || (JobGrade = {}));
```

## 陸、明文型別 X 格式為王 - Literal Types
![](https://i.imgur.com/sSiAehP.png)

只要是表達廣義物件的格式或者是任意型別（包含原始型別的）複合組合（union 與 intersection 也算在內就隸屬於明文型別的範疇。
![](https://i.imgur.com/N65oyYE.png)

![](https://i.imgur.com/VuQ6OYz.png)
    
### 一、型別化名 Type Alias
型別化名的主要目的為簡化程式碼以及進行型別的抽象化（Type Abstraction）

```typescript=
// 原本的型別太過複雜
let powerOp: (n1: number, n2: number) => number = (n1: number, n2: number) => {
  return n1 ** n2
}

// 加上 Type Alias 進行簡化
type MathOperator = (n1: number, n2: number) => number
let powerOpTypeAlias: MathOperator = (n1: number, n2: number) => n1 ** n2
```

- 函式型別的化名
任何變數 A 被型別化名 U 註記，則該變數被指派到的函式值，不需要積極註記，因為早在定義化名的時候，這個步驟就被做掉了 => 函式型別不用積極註記的第二種情況
![](https://i.imgur.com/ETxZdeu.png)

- 廣義物件的積極註記
```typescript=
type PersonInfo = {
  name: string,
  age: number, 
  hasPet: boolean
}

function printInfo(info: PersonInfo) {
  console.log(info.name)
  console.log(info.age);
  console.log(info.hasPet);
}

printInfo({
  name: 'Martin',
  age: 28,
  hasPet: false,

  hello: 'John', // ts 提示錯誤
  nothingSpecial: null,
})
```
如果再變數裡的物件，只要明文型別有符合，不要減少，就算多出鍵值對也能通過TS
因此**任何變數需要存取廣義物件時，必須進行積極註記型別的動作。**
```typescript=
let infoAboutMartin = {
  name: 'Martin',
  age: 28,
  hasPet: false,

  hello: 'John',
  nothingSpecial: null,
}

printInfo(infoAboutMartin) // 通過TS
```
    
## 柒、選用屬性 X 型別擴展 - Optional Properties
![](https://i.imgur.com/R0GBJeb.png)

### 一、 使用<prop>?選用屬性註記
當物件內的屬性，不是必須出現的狀況，可以使用 Optional Properties
![](https://i.imgur.com/tC5WUgX.png)

- 若某屬性 P 屬於某物件的明文型別 的屬性之一，且該屬性對應的型別值為 T，而 A 是該明文型別的別名，則：
```
type A = {
  P?: T
};    
```
代表：
    1. 選擇性地忽略 P 這個屬性。
    2. 因為推論出來的結果會是以下的形式，因此也可以選擇寫出 P 屬性但填入 undefined 這個值：
```
{ P?: T | undefined }
```
    
### 二、複合類別
![](https://i.imgur.com/rUzkxnz.png)

### 三、元組型別的選用元素
![](https://i.imgur.com/pjxdxpQ.png)


## 捌、特殊型別 - Never Type
![](https://i.imgur.com/esKA2xp.png)

- 無法跳脫出該函式或方法
- 出現例外結果中斷執行
- never 型別為所有型別的 subtype
![](https://i.imgur.com/rK16cKS.png)

## 玖、特殊型別 - Any
真的非不得已狀態下或者是快速測試下，可以使用 any。不過開發上，儘量不要用到 any 比較好；或者真不巧，遇到 any，也應當主動註記。
### 一、出現時機
- **遲滯性指派 Delayed Iniitialization**：變數定義時，除了未加註記（Type Annotation）外，也沒有指派值或者被指派為 Nullable Types。
- **一般宣告下的函式參數**：一般被宣告的函式，其參數通常會直接被推論為 any，又被稱作 Implicit any 的情形。此狀況是少數會被 TypeScript 主動通報的
- **函式回傳之值**：有些實務上，型別無法確定，因此到最後只能將回傳值預設為 any（如：JSON.parse）
- **未註記之空陣列**：沒有積極型別註記到的空陣列，其預設推論為 any[]
- **跟 I/O 行為有關**：例如，從外部 CSV 檔案讀取表格行格式（通常用陣列或元組型別），若沒有特殊註記的話，通常會用 any 作表示
    
## 拾、特殊型別 - Unknown Type
![](https://i.imgur.com/ECHf28n.png)

> unknown 相對 any 來說，是一種更安全的型別機制

### 1. unknown 的可以與不可以
- 只要當變數被註記為 any 或 unknown，該變數照樣都可以接收任意型別的值。
![](https://i.imgur.com/JdYuDx8.png)

- unknown 型別的值不能被強行指派到除了 any 或 unknown 型別外的任意型別變數
![](https://i.imgur.com/8ulSEf7.jpg)
![](https://i.imgur.com/HMQTfpW.png)
![](https://i.imgur.com/IAQke4d.png)
    - 1. 只要程式根據判斷式與敘述式的結構，縮小變數在型別推論上的範疇，我們就可以讓純 unknown 型別的變數被指派到任意型別上
    ![](https://i.imgur.com/P3R1rVY.png)
    - 2. 顯性的型別註記
    ![](https://i.imgur.com/LzgwIT4.png)

- 被標記為 unknown，不能呼叫任何方法或屬性，亦不可作為任何函式或方法之參數），any 型別不管亂呼叫什麼東西，都不會有事。
![](https://i.imgur.com/JgaKxKX.png)
![](https://i.imgur.com/TOA0Iu1.png)
    - 若 unknown 變數被顯性地型別註記為某型別 T（其中 T 不為 unknown），則 unknown 變數可以作為該型別 T 之代表值，進行該型別底下合理之操作
    ![](https://i.imgur.com/y1GlAoq.png)
    - 若 unknown 變數被控制流程限縮型別至某型別 T（其中 T 不為 unknown），則 unknown 變數可以作為該型別 T 之代表值，在該控制流程的範圍內進行合理之操作
    ![](https://i.imgur.com/kdoM8N3.png)

### 2.寫一個安全的函式（或方法）把不安全的函式（或方法）包裝起來
把 JSON.parse 這種會回傳 any 的方法函式包裝起來。
![](https://i.imgur.com/47vB9CK.png)


### 3. unknown 型別進行複合

type U = unknown & T
=> T
    

type U = unknown | T
=> unknown
    
type U = unknown | any
=> any

## 拾壹、型別化名
![](https://i.imgur.com/0XPOvCI.png)

型別化名的意義就是把複雜格式（尤其是明文格式）的型別進行程式碼簡化與抽象化
### 一、用法
若某型別 T，
    
**T 可為任何的型別**: 
- **原始型別、
物件型別、
TypeScript 內建型別、
明文型別、
複合型別、
Generics 通用型別**等

其中我們想要讓該型別 T 等效於別名 A，則可以使用 TypeScript 的 type 關鍵字進行化名宣告：
```
type A = T
```
![](https://i.imgur.com/U2zx3jt.png)

## 拾貳、介面宣告 X 使用介面 - TypeScript Interface Intro.．
![](https://i.imgur.com/aF3scLO.png)

TypeScript Interface 可以藉由關鍵字 interface 宣告出來，介面裡面的詳細定義可為：
- **物件格式**：即 JSON 格式，是為屬性對型別，不是對值
- **單一函式格式**：沒有任何屬性，就是函式而已，但不一定需要標上函式名稱
- **混合格式**：即『物件格式』與『單一函式格式』混合在一起

![](https://i.imgur.com/OFxbQR6.png)

### 一、interface 檢查機制
- 多一鍵少一鍵都不行
![](https://i.imgur.com/tJOwQw9.png)

- 如果講物件帶入變數，再放進函式裡面，只要不少於 interface 定義的型別就不會出錯
![](https://i.imgur.com/nKfF79P.png)
- 為變數積極註記
![](https://i.imgur.com/WyeQIzT.png)
### 二、interface 的介面擴展（Interface Extension / Inheritance）
![](https://i.imgur.com/pJr2DRL.png)
- 多個介面要進行延伸，其中的兩個介面互不相容，就不能進行擴展的動作。
![](https://i.imgur.com/ESPN3hi.png)
    
    
### 三、介面 Interface V.S. 型別 Type
>- **介面（Interface）的意義** —— 跟規格的概念很像，可以擴充設計、組裝出更複雜的功能規格
> - **型別（Type）的意義** —— 代表靜態的資料型態，因此型別一但被定義出來則恆為固定的狀態。儘管可以利用型態的複合（intersection 與 union）看似達到型別擴展的感覺，然而這個行為並不叫作型別擴展，而是創造出新的靜態型別
    
- 介面使用上比較偏實作面，下面程式碼定義用戶帳號，而用戶帳號由"帳戶系統"和"帳戶個人資料"組成，藉由 interface 就可以把資料拆分的更細，讓管理程式變得輕鬆
![](https://i.imgur.com/9yt5pVG.png)

- interface 單字可以類比為 TypeScript 的介面，而 implementation 單字可以類比為型別系統裡的 type。
    - 介面：規格（Spec）的概念，可以組裝、延展（使用 extends）
    - 型別：靜態的資料格式，不能被延展，每一次宣告新的型別化名 —— 對型別進行複合形式的操作 —— 都是在定義新的型別，不是延展作用
## 拾参、函式超載 X 究極融合 - Function Overload & Interface Merging
![](https://i.imgur.com/ees1OnD.png)ㄋ功能多樣性 X 多樣性介面 - More on TypeScript Interface
    
### 一、函數超載
兼容不同情況函數輸入與輸出的型別註記
- 介面定義的屬性對應的函式可以- 進行超載的動作。
- 被超載的函式名稱必須相同。
- 若某物件實踐該介面時，必須符合該介面裡超載過的函式之所有情形
- 單純函式形式的介面也可以進行函式超載，差別在沒有名稱標記而已。
![](https://i.imgur.com/GCeyRL1.png)

### 二、介面融合
- 若某介面 I 被重複定義多次，則該介面到最後的推論結果會是所有重複定義的介面的交集。
- I 若被重複定義時，裡面若干屬性跟過去所定義的某屬性相符的話，該屬性的型別必須跟過往定義出的介面裡的屬性之型別吻合。
![](https://i.imgur.com/5x4S11V.png)

- 整合第三方套件範例
![](https://i.imgur.com/VgJbGnz.png)

## 拾肆、功能多樣性 X 多樣性介面 - More on TypeScript Interface
![](https://i.imgur.com/e0MpDGf.png)

### 一、Indexable Types - 模仿部分廣義物件的行為
indexable Types 在介面及型別都能使用
- 固定屬性的型別 - 對應 - 固定值的型別
![](https://i.imgur.com/dWE9pv0.png)

- Warning
    - 不能直接用陣列形式初始化值（除非是空陣列），由於陣列屬於 JS 物件的一種，而物件的屬性初始化時不允許為 string 以外的型態，因此初始化陣列的索引（index）都會以 '0', '1', '2' ... 這種字串的數字形式初始化，所以才會被 TypeScript 判定結果是錯誤！
    - 空陣列可以被初始化則是因為 TypeScript 認為都沒有屬性，沒有檢測之必要
    - [index: number] 將索引部分鎖定在 number 型別上，目的是為了防止開發者呼叫字串型別的屬性（或是用點的方式呼叫屬性），而是模擬陣列的行為 -- 用數字來檢索該物件裡的內容
    - 當物件必須在 [index: number] 這種狀態下初始化時，必須用 JSON 物件的格式，指定索引的位置（數值）並填入對應的值（當然，值必須符合型別 T，其中 T 為 [index: number]: T 裡面的 T）
```
[keyName: TKey]: TValue 
```
- TKey 必須為 number 或者是 string 其中一種，不能為其他型別與 number 和 string 的複合格式（連 number | string 是不接受的！）
- TValue 可為任意型別
    
### 二、唯讀屬性 Readonly
在屬性前加入 readonly 的關鍵字，該屬性就會變成唯讀模式（Read-Only）。
![](https://i.imgur.com/zluCbwf.png)
![](https://i.imgur.com/nhUw8Jn.png)
### 三、介面的混合格式 Hybrid Type Interface
- 混合格式：即將『物件格式』跟『單一函式格式』混合在一起

![](https://i.imgur.com/S96VdGQ.png)
![](https://i.imgur.com/jBm52xX.png)

- 忘記實踐出混合型態介面裡的屬性與方法，TS 是不會檢查的
    
## 拾伍、型別檢測 Type Guard
- 控制流程分析
- 推論被限縮
![](https://i.imgur.com/guBEngh.png)
![](https://i.imgur.com/hkkDCji.png)
### 一、行為限縮的技巧
- 若想要過濾出純原始型別的值的話，使用 typeof 操作子
- 若想要過濾出廣義物件型別的值的話，使用 instanceof 判斷操作子，並填上屬於該物件型別所屬的類別
- 其他方式，譬如 Array.isArray 可以檢測陣列