联合类型
如果希望一个变量可以支持多种类型,就可以用联合类型(union types)来定义。
例如,一个变量既支持 number 类型,又支持 string 类型,就可以这么写:
type Nuion = number | string
let num: Nuion = 1024
// 联合类型大大提高了类型的可扩展性,
//但当 TS 不确定一个联合类型的变量到底是哪个类型的时候,只能访问他们共有的属性和方法。
num.length // 报错
//如果直接访问 `length` 属性,string 类型上有,number 类型上没有,就报错了
交叉类型
如果要对对象形状进行扩展,可以使用交叉类型 &。
比如 Person 有 name 和 age 的属性,而 Student 在 name 和 age 的基础上还有 grade 属性,就可以这么写
interface Person {
name: string
age: number
}
type Student = Person & { grade: number }
//这和类的继承是一模一样的,这样 Student 就继承了 Person 上的属性,
联合类型 | 是指可以取几种类型中的任意一种,而交叉类型 & 是指把几种类型合并起来。
交叉类型和 interface 的 extends 非常类似,都是为了实现对象形状的组合和扩展。
类型收窄
如果有一个 getLength 函数,入参是联合类型 number | string,返回入参的 length。
从上文可知,这么写会报错,因为 number 类型上没有 length 属性
这个时候,类型收窄(Type Guards)出现了
使用typeof
const f1 = (a:number | string){
if(typeof a === 'number'){
a.toFixed()
}else if( a === 'string'){
a.split(',')
}else{
a
}
}
// typeof无法区分对象的具体类型
const f1 = (a:Date | Array){
typeof a // 返回的都是object
}
使用Instanceof
const f1 = (a:Array<Date> | Date)>={
if(a instaceof Date){
a.getDay()
}else if( a instanceof Array){
a[0].getDay()
}else{
throw new Error('333')
}
}
// instaceof检索对象原型 不支持简单类型 string
以上两种不支持TS独有的类型,type | interface(因为类型擦除)
使用in 操作符
JavaScript 中有一个 in 操作符可以判断一个对象是否有对应的属性名。TypeScript 也可以通过这个收窄类型。
只适用于普通对象
type Person = {
name: string
}
const f1 = (a:Person | Person[]) =>{
if('name' in a ){
a // Persion
}else{
a //Persion[]
}
}
还可以使用JS中的isArray等方法。。。(以上方法都是用JS实现的,但JS的类型系统很鸡肋)
使用类型谓词/is
type Person {
age:number
height:number
}
type Aninal {
width:[number,number]
num:number
}
const f1 (a:Person | Aninal):boolean{
if(isPerson(a)){
a // 此处a就是Person类型
}
}
function isPerson(b:Person | Aninal): b is Person{
return 'age' in Person && 'height' in Person
}
//is支持所有对象类型 但缺点就是写起来太麻烦。。。还不容易理解