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块中是否包含了所有分支

TypeScript实战-16-TS高级类型-联合类型_第1张图片

2,利用never类型

在switch-default中,将未捕捉到的类型赋值给never,检查s是否是never类型

TypeScript实战-16-TS高级类型-联合类型_第2张图片
在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对联合类型的约束

你可能感兴趣的:(TypeScript,TypeScript)