主题
协变和逆变
协变
子类型赋值给父类型的情况就叫做协变
比如有两个以下两个类型
typescript
interface Person {
name: string;
age: number;
}
interface Musi {
name: string;
age: number;
hobbies: string[]
}
Musi 是 Person 的子类型,更具体,那么 Musi 类型可以赋值给 Person 类型
typescript
let person: Person = {
name: '',
age: 23
}
let musi: Musi = {
name: 'musi',
age: 23,
hobbies: ['sing', 'play game']
}
person = musi // ok
逆变
父类型赋值给子类型的情况就叫做逆变,只有函数的参数有逆变性质
比如有两个以下两个函数
typescript
let printHobbies: (musi: Musi) => void
printHobbies = (musi) => {
console.log(musi.hobbies)
}
let printName: (person: Person) => void
printName = (person) => {
console.log(person.name)
}
printHobbies = printName // ok
printName = printHobbies // error
printName 的参数 Person 不是 printHobbies 的参数 Musi的父类型么,为啥能赋值给子类型?
因为这个函数调用的时候是按照 Musi来约束的类型,但实际上函数只用到了父类型 Person 的属性和方法,当然不会有问题,依然是类型安全的。
那反过来呢,如果 printHoobies 赋值给 printName 会发生什么?
因为函数声明的时候是按照 Person 来约束类型,但是调用的时候是按照 Musi 的类型来访问的属性和方法,那自然类型不安全了,所以就会报错
类型父子关系的判断
在 ts 中,只要结构上是一致的,那么就可以确定父子关系,这种叫做结构类型系统
typescript
interface Person {
name: string;
age: number;
}
interface Musi {
name: string;
age: number;
hobbies: string[]
}
Person 和 Musi 没有 extends 关系,但在 ts 上,它们确实是父子关系
通过结构确定父子关系,更具体的那个是子类型
注意,这里用的是更具体,而不是更多。
判断联合类型父子关系的时候, 'a' | 'b' 和 'a' | 'b' | 'c' 哪个更具体?
'a' | 'b' 更具体,所以 'a' | 'b' 是 'a' | 'b' | 'c' 的子类型。