所谓类型兼容性,就是用于确定一个类型是否能赋值给其他的类型

TS中的类型兼容性是基于结构类型的(也就是形状),如果A要兼容B,那么A至少具有和B相同的属性

协变

又称鸭子类型

一只鸟,走路像鸭子,游泳也像鸭子,做什么都像鸭子,但它并不是鸭子,那么这只鸟就可以成为鸭子类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
interface A {
name:string
age:number
}
// B类型有着A类型的所有属性
interface B {
name:string
age:number
gender:string
}

let a:A = {
name:"yajue",
age:24
}
let b:B = {
name:"snnn",
age:30,
gender:"女"
}
// b = a // 不OK
a = b // OK,产生了协变(类似java的多态)

逆变

逆变通常发生于函数的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
interface A {
name:string
age:number
}
// B类型有着A类型的所有属性
interface B {
name:string
age:number
gender:string
}

let fna = (param:A)=> {}
let fnb = (param:B)=> {}
// fna = fnb // 不OK
fnb = fna // OK,产生了逆变
// 虽然fnb的参数类型是B,实际上执行的是fna的函数体
// 在函数体中使用所有A类型的属性都是安全的,反之不安全
fnb()

双向协变

在tsconfig.json中设置

1
"strictFunctionTypes": false

开启后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
interface A {
name:string
age:number
}

// B类型有着A类型的所有属性
interface B {
name:string
age:number
gender:string
}

let a:A = {
name:"yajue",
age:24
}
let b:B = {
name:"snnn",
age:30,
gender:"女"
}
// b = a // 照样不OK
a = b // OK

let fna = (param:A)=> {}
let fnb = (param:B)=> {}
fna = fnb // OK
fnb = fna // OK