上一篇介绍了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块中是否包含了所有分支
2,利用never类型
在switch-default中,将未捕捉到的类型赋值给never,检查s是否是never类型
在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对联合类型的约束