TypeScript實戰-16-TS高級類型-聯合類型

一,前言

上一篇介紹了TS高級類型-交叉類型
本篇介紹另一個TS高級類型-聯合類型

聯合類型並不陌生,之前已經接觸過多次了

二,簡單的聯合類型

聯合類型:

聲明時,類型可能爲多個類型中的一種,但不能確定是哪一種
let a: number | string = 1
let b: number | string = "1"

三,字面量聯合類型

字面量類型:

不僅限定變量類型,還限定變量的取值範圍

字面量聯合類型:

let c: 1 | 2 | 3 = 1
let d: '1' | '2' | '3' = '1'

四, 對象聯合類型

還是使用之前的例子:

// 對象聯合類型
// 聲明兩個接口:包含相同和不同方法各一個
interface JavaInterface {
    helloJava(): void
    build(): void
}
interface JavaScriptInterface {
    helloJavascript(): void
    build(): void
}
// 定義兩個類,分別實現兩個接口
class Java implements JavaInterface {
    helloJava() {}
    build() {}
}
class JavaScript implements JavaScriptInterface {
    helloJavascript() {}
    build() {}
}
// 定義枚舉Type
enum Type { Strong, Week }
// 根據類型獲取實例
function getLanguage(type: Type) {
    let lang = type === Type.Strong ? new Java() : new JavaScript()
    return lang
}

根據類型獲取實例的getLanguage方法中,lang爲聯合類型
這時,對象類型並不能確定,到底是Java還是JavaScript
所以此時,是不能訪問helloJava和helloJavascript的,只能訪問共有的build方法


五,可區分的聯合類型

這種模式本質上是結合聯合類型和字面量類型的一種類型保護方法

原理:

如果一個類型是多個類型的聯合類型,且多個類型間有一個公共屬性
那麼,就可以利用這個公共屬性,創建不同的類型保護區塊
// 聲明兩個接口Square,Rectangle,都有kind屬性表示類型
// 正方形
interface Square {
    kind: 'square'
    side: number    // 邊長
}
// 長方形
interface Rectangle {
    kind: 'rectangle'
    width: number   // 寬
    height: number  // 高
}
// 使用類型別名聲明Square和Rectangle的聯合類型Shape
type Shape = Square | Rectangle
// 計算面積:利用兩種類型共有的kind屬性,創建不同的類型保護區塊
function area(s: Shape) {
    switch (s.kind){
        case 'square':
            return s.side * s.side
        case 'rectangle':
            return s.height * s.width
    }
}

添加Circle

// 正方形
interface Square {
    kind: 'square'
    side: number    // 邊長
}
// 長方形
interface Rectangle {
    kind: 'rectangle'
    width: number   // 寬
    height: number  // 高
}
// 圓
interface Circle {
    kind: 'circle'
    r: number   // 半徑
}
type Shape = Square | Rectangle | Circle
// 計算面積:利用兩種類型共有的kind屬性,創建不同的類型保護區塊
function area(s: Shape) {
    switch (s.kind){
        case 'square':
            return s.side * s.side
        case 'rectangle':
            return s.height * s.width
    }
}

這時發生一個問題:

area方法中並未添加circle的計算邏輯,但代碼沒有報錯

如果此時運行代碼將得到結果爲undefined:

console.log(area({kind: 'circle', r: 1}))	// undefined

這種情況需要使用TS進行約束:

1,爲函數指定明確的返回值類型

爲函數指定明確的返回值類型,那麼TS就會判斷Switch塊中是否包含了所有分支

case

2,利用never類型

在switch-default中,將未捕捉到的類型賦值給never,檢查s是否是never類型

default
在default中檢查未被之前case捕捉到的類型是否爲never類型
如果s是never類型,說明前面的所有分支都被覆蓋了,這個分支永遠不會走到
如果s不是never類型,說明前面的分支有遺漏,需要補上這個分支

正確的代碼:

// 正確的寫法
function area(s: Shape) {
    switch (s.kind){
        case 'square':
            return s.side * s.side
        case 'rectangle':
            return s.height * s.width
        case 'circle':
            return Math.PI * s.r ** 2
        default:
            return ((e: never) => {
                throw new Error(e)
            })(s)
    }
}
console.log(area({kind: 'circle', r: 1}))   // 3.141592653589793

六,結尾

本篇介紹了TS高級類型-聯合類型,包括:

1,簡單的聯合類型
2,字面量聯合類型
3,對象聯合類型
4,可區分的聯合類型
5,TS對聯合類型的約束
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章