1. 名义类型兼容性
1.1 概念:
通过明确的声明或类型的名称决定。
1.2 类型:
- any :兼容除never外的所有类型,可被所有类型兼容。
- never :兼容所有类型,可被never类型兼容。
- unknown :兼容any,可被所有类型兼容。
- void :兼容any、unknown类型,可被any、never、null、undefined兼容。
- null :兼容any、unknown、undefined类型,可被any、never、undefined兼容。
- undefined :兼容any、unknown、null类型,可被any、never、null兼容。
- enum :与数字类型相互兼容。
2. 结构类型兼容性
2.1 概念
对值所具有的结构进行类型检查。如果类型A要兼容类型B,则类型B至少要具有与类型A相同的属性。
2.2 父子类型
type ParentRef= '1' | '2' | '3';
type ChildRef= '1' | '2';
let parent: ParentRef;
let child: ChildRef;
parent = child; // 兼容
child = parent; // 不兼容
interface Parent { // 父类型
name: string
}
interface Child{ // 子类型
name: string;
age: string
}
父子类型特点:
-
子类型属性更多,比父类型更具体。
-
子类型一定可以赋值给父类型。
2.3 变型
2.3.1 协变
特点: 子类型可以赋值给父类型。函数返回值类型属于协变。
interface A {
name: string
}
interface B {
name: string
age: number
}
let a:A = {
name: "小红",
age: 20,
}
let b:B = {
name: "小明",
age: 21
}
a = b // true
2.3.2 逆变
特点:父类型可以赋值给子类型。函数的参数类型属于逆变。
let fna = (params:A) => {}
let fnb = (params:B) => {}
fna = fnb // false
fnb = fna // true
2.3.3 不变
特点: 如果两个类型不完全相同,则不能兼容,无法构成父子类型关系。
interface A {
name: string
}
interface B {
age: number
}
let a:A = {
name: "小红"
}
let b:B = {
age: 21
}
a = b // false
2.3.4 双向协变
tsconfig.json中将strictFunctionTypes设置为false,可支持双向协变。