交叉类型(&)
交叉类型是将多个类型合并为一个类型。这让我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。语法:T & U
其返回类型既要符合 T 类型也要符合 U 类型
联合类型(|)
联合类型与交叉类型很有关联,但是使用上却完全不同。
语法:T | U
其返回类型为连接的多个类型中的任意一个
类型约束(extends)
语法:T extends K
这里的 extends 不是类、接口的继承,而是对于类型的判断和约束,意思是判断 T 能否赋值给 K
可以在泛型中对传入的类型进行约束。
const copy = (value: string | number): string | number => value
// 只能传入 string 或者 number
copy(10)
// 会报错:Argument of type 'boolean' is not assignable to parameter of type 'string | number'
// copy(false)
类型映射(in)
会遍历指定接口的 key 或者是遍历联合类型。
类型谓词(is)
语法:parameterName is Type
parameterName 必须是来自于当前函数签名里的一个参数名,判断 parameterName 是否是 Type 类型。
具体的应用场景可以跟着下面的代码思路进行使用:
看完联合类型的例子后,可能会考虑:如果想要在 start 函数中,根据情况去调用 Bird 的 fly 方法和 Fish 的 swim 方法,该如何操作呢?
首先想到的可能是直接检查成员是否存在,然后进行调用:
function start(pet: Bird | Fish) {
// 调用 layEggs 没问题,因为 Bird 或者 Fish 都有 layEggs 方法
pet.layEggs();
if ((pet as Bird).fly) {
(pet as Bird).fly();
} else if ((pet as Fish).swim) {
(pet as Fish).swim();
}
}
但是这样做,判断以及调用的时候都要进行类型转换,未免有些麻烦,可能会想到写个工具函数判断下:
function isBird(bird: Bird | Fish): boolean {
return !!(bird as Bird).fly;
}
function isFish(fish: Bird | Fish): boolean {
return !!(fish as Fish).swim;
}
function start(pet: Bird | Fish) {
// 调用 layEggs 没问题,因为 Bird 或者 Fish 都有 layEggs 方法
pet.layEggs();
if (isBird(pet)) {
(pet as Bird).fly();
} else if (isFish(pet)) {
(pet as Fish).swim();
}
}
待推断类型(infer)
可以用 infer P 来标记一个泛型,表示这个泛型是一个待推断的类型,并且可以直接使用。可以应用于判断 T 是否能赋值给 (param: infer P) => any,并且将参数推断为泛型 P,如果可以赋值,则返回参数类型 P,否则返回传入的类型。
原始类型保护(typeof)
语法:typeof v === "typename" 或 typeof v !== "typename"
用来判断数据的类型是否是某个原始类型(number、string、boolean、symbol)并进行类型保护
"typename"必须是 "number", "string", "boolean"或 "symbol"。但是 TypeScript 并不会阻止你与其它字符串比较,语言不会把那些表达式识别为类型保护。
类型保护(instanceof)
与 typeof 类似,不过作用方式不同,instanceof 类型保护是通过构造函数来细化类型的一种方式。
instanceof 的右侧要求是一个构造函数,TypeScript 将细化为:
此构造函数的 prototype 属性的类型,如果它的类型不为 any 的话
构造签名所返回的类型的联合。
索引类型查询操作符(keyof)
语法:keyof T
对于任何类型 T, keyof T 的结果为 T 上已知的 公共属性名 的 联合
索引访问操作符(T[K])
语法:T[K]
类似于 js 中使用对象索引的方式,只不过 js 中是返回对象属性的值,而在 ts 中返回的是 T 对应属性 P 的类型