一. | 分隔符
在 TypeScript 中联合类型(Union Types)表示取值可以为多种类型中的一种,联合类型使用 | 分隔每个类型。联合类型通常与 null 或 undefined 一起使用:
const sayHello = (name: string | undefined) => { /* ... */ };
以上示例中 name 的类型是 string | undefined 意味着可以将 string 或 undefined 的值传递给 sayHello 函数。
sayHello("semlinker");
sayHello(undefined);
此外,对于联合类型来说,你可能会遇到以下的用法:
let num: 1 | 2 = 1;
type EventNames = 'click' | 'scroll' | 'mousemove';
示例中的 1、2 或 ‘click’ 被称为字面量类型,用来约束取值只能是某几个值中的一个。
二. & 运算符
在 TypeScript 中交叉类型是将多个类型合并为一个类型。通过 & 运算符可以将现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。
type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };
let point: Point = {
x: 1,
y: 1
}
在上面代码中我们先定义了 PartialPointX 类型,接着使用 & 运算符创建一个新的 Point 类型,表示一个含有 x 和 y 坐标的点,然后定义了一个 Point 类型的变量并初始化。
同名基础类型属性的合并
那么现在问题来了,假设在合并多个类型的过程中,刚好出现某些类型存在相同的成员,但对应的类型又不一致,比如:
interface X {
c: string;
d: string;
}
interface Y {
c: number;
e: string
}
type XY = X & Y;
type YX = Y & X;
let p: XY;
let q: YX;
为什么接口 X 和接口 Y 混入后,成员 c 的类型会变成 never 呢?这是因为混入后成员 c 的类型为 string & number,即成员 c 的类型既可以是 string 类型又可以是 number 类型。很明显这种类型是不存在的,所以混入后成员 c 的类型为 never。
三. 类型谓词(is关键字)
当使用联合类型时,我们必须尽量把当前值的类型收窄为当前值的实际类型,而类型保护就是实现类型收窄的一种手段。
类型保护是可执行运行时检查的一种表达式,用于确保该类型在一定的范围内。换句话说,类型保护可以保证一个字符串是一个字符串,尽管它的值也可以是一个数字。类型保护与特性检测并不是完全不同,其主要思想是尝试检测属性、方法或原型,以确定如何处理值。
目前主要有四种的方式来实现类型保护:
- in 关键字;
- typeof 关键字;
- instanceof 关键字;
- 自定义类型保护的类型谓词(type predicate)
因为前三种比较常见,现在主要来看自定义类型保护的类型谓词
举例
type Student = {
type: string;
name: string;
classRoom: string;
};
type Teacher = {
type: string;
name: string;
officeRoom: string;
};
type A = Student | Teacher;
const isTeacher = (params:A) => {
return params.type === "teacher"
}
const fu = (params:A) => {
if(isTeacher(params)) {
console.log(params.officeRoom)
}
}
会有如下报错
解决方法
const isTeacher = (params:A):params is Teacher => {
return params.type === "teacher"
}
应用场景:
在TypeScript中,我们往往会定义一个联合类型,来解决一些业务中复杂数据的处理。
当某个元素的类型是联合类型,取值时,当所访问属性为联合类型的公共属性(即交叉属性时)
TypeScript判定无风险,可用。但我们使用不交叉的属性时候,TypeScript会报错,报错信息如上。
- 解决联合类型问题的方法
(1) 将所有非交叉属性设置 为可选属性;
(2) 使用断言(as);
(3) 类型谓词(is)