类型兼容
大约 2 分钟
类型兼容
所谓类型兼容,就是用于确定一个类型是否能赋值给其他的类型。
ts 中的类型兼容是基于结构类型的,如果 A 要兼容 B,那么 A 至少要具有和 B 相同的属性,即 A 和 B 的交集为 A(A ∩ B = A
)。如下:
interface A {
name: string
age: number
}
interface B {
name: string
age: number
sex: string
}
let a: A = {
name: "zhangsan",
age: 18,
}
let b: B = {
name: "lisi",
age: 20,
sex: "man",
}
a = b // 不报错
上面这段代码中a = b
不报错的原因就是接口 A 可以兼容接口 B,B 和 A 拥有相同的属性,只不过 B 比 A 还额外多了别的属性。这就叫做协变。
协变
协变也叫鸭子类型:即如果有一只鸟,它走路像鸭子,游泳像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。
上面的例子就展示了协变,A 和 B 是两个不同的接口,但是由 B 定义的变量可以赋值给由 A 定义的变量,但是反过来就不行。
兼容其他类型的这个类型,必须有和被兼容类型完全相同的属性,至于它有没有其他另外的属性无所谓,但是不能缺失被兼容类型中的任一属性。
逆变
逆变一般发生在函数参数上,如:
interface A {
name: string
age: number
}
interface B {
name: string
age: number
sex: string
}
let fnA = (a: A) => {}
let fnB = (b: B) => {}
fnA = fnB // 报错
fnB = fnA // 不报错
在这个代码中,我们可以看到,fnA 和 fnB 的不同点在于参数类型不同,但是与协变不一样的是,这里是 A 能赋给 B,但 B 不能赋给 A,这就是逆变。
双向协变
即实现上面代码中fnA = fnB && fnB = fnA
都不报错,一般 ts 是禁止的,因为可能会造成一些漏洞,但是如果想使用的话就可以在tsconfig.json
中将"strictFunctionTypes"
改为true
。