一,前言
本篇只要讨论TS不同类型的兼容性
类型兼容经常发生在接口,函数和类中
二,类型兼容
如果类型A可以被赋值给类型B,那么就可以说类型B兼容类型A
如果 : B(目标类型) = A(源类型) , 则 : 类型B兼容类型A
之前的例子中,我们就遇到过number和null的兼容问题:
在strictNullChecks = false时(默认true),字符串变量是可以被赋值为null类型的
tsconfig.json
...
"strictNullChecks": false,
...
此时,number类型可以兼容null类型,也就是null类型是number类型的子类型
TS允许不同类型的变量之间相互赋值,从某种程度上产生了不可靠性,同时增加了TS语言的灵活性
三,接口的兼容性
测试接口之间的兼容性:
定义两个接口X和Y,X含有ab属性,Y含有abc属性
定义两个变量x和y,分别指定为X和Y的接口类型
将变量y赋值给变量x,测试接口X是否兼容接口Y
将变量x赋值给变量y,测试接口Y是否兼容接口X
可以看出:
源类型必须具备目标类型的全部必要属性,才可以被赋值
可以这样理解:
接口类型相当于对变量属性的约束,必须全部满足才可以兼容赋值
四,函数的兼容性
一般地,当两个函数相互赋值时,就发生函数兼容,
例如方法的参数为一个函数类型,当调用该方法传参时,就会发生函数兼容
此时,函数类型的这个参数就是目标类型,将要传入的参数为源类型
构造用于测试的样例:
首先,使用type关键字定义一个函数类型Handler(包含两个参数),
然后,使用此函数作为高阶函数foo的参数
高阶函数定义: 以函数作为参数的函数
// 使用type关键字定义一个函数类型(包含两个参数)
type Handler =(a: number, b: number) => void
// 使用函数类型Handler作为高阶函数foo的参数
function foo(handler: Handler) {
return handler
}
要想使目标函数能够兼容源函数,需同时满足以下三个条件:
1,参数的个数
目标函数的参数个数一定要多于源函数的参数个数
2,参数的类型
参数类型必须匹配
3,返回值的类型
目标函数的返回值类型 与 原函数的返回值类型 必须相同或为其子类型
五,函数兼容性的影响因素1-参数个数
目标函数的参数个数一定要多于源函数的参数个数
当参数固定时,多参,少参情况下的兼容性:
当参数不固定时,固定参数与可选参数,剩余参数的兼容性
可以看到:
固定参数 可兼容 可选参数 和 剩余参数
可选参数 不兼容 固定参数 和 剩余参数(strictFunctionTypes = true时)
可选参数 可兼容 固定参数 和 剩余参数(strictFunctionTypes = false时)
剩余参数 可兼容 固定参数 和 可选参数
结论:
目标函数的参数个数一定要多于源函数的参数个数
即:在确保 目标函数参数个数 > 源函数参数个数时, 才可能兼容
可选参数 和 剩余参数不能保证一定被传入,所以不一定兼容(即严格模式下不兼容)
联想理解:
可以使用插线板插头进行联想理解
目前很多3相插座可同时支持2相插头和3相插头接入
此时,插座相当于"目标",插头相当于"源",
所以,我们说这种3相插座是可以兼容2相插头和3相插头的
而普通的2相插座是不能兼容3相插头的,因为3相插头多一个头...
六,函数兼容性的影响因素2-参数类型
参数类型必须匹配
基础类型:
对象类型:
同样可以使用插座和插头的记忆方式:参数多的兼容参数少的
也可以通过修改strictFunctionTypes配置项,可以使函数兼容
tsconfig.json
...
"strictFunctionTypes": true,
...
函数参数的双向协变:
函数的参数之间可以相互的赋值的情况,叫函数参数的双向协变
七,函数兼容性的影响因素3-返回值类型
目标函数的返回值类型 与 源函数的返回值类型 必须相同或为其子类型
记忆方式:
返回值类型,和接口类似相当于是对函数的一种约束,所以必须在满足要求的前提先才可以兼容
即参数可以多了我不用,但绝对不可以少
八,函数重载对函数兼容性的影响
继续使用之间介绍函数重载的例子:
定义两个重载函数,并实现
此时,重载列表中的函数为目标函数,实现函数为源函数
// 函数重载对函数兼容性的影响
// 函数定义-重载列表
function overload(a: number, b: number): number
function overload(a: string, b: string): string
// 函数实现
function overload(a: any, b: any): any {}
从重载函数的运行机制分析重载函数的兼容性:
前面我们介绍过,重载函数的实现是一个类型较为宽泛的函数
运行时,TS编译器会按顺序去重载列表一一进行匹配,并使用第一个匹配的函数定义执行
所以,目标函数(重载列表中的函数)的参数个数 要大于等于 源函数(实现函数)的参数
返回值类型也要符合相应要求
兼容 : 目标函数参数个数 > 源函数参数个数
不兼容 : 目标函数参数个数 < 源函数参数个数
重载函数返回值类型不兼容:
九,枚举类型的兼容性
枚举类型和数值类型是可以完全互相兼容的
// 枚举类型的兼容性
enum EnumA {
ItemA1,
ItemA2
}
enum EnumB {
ItemB1,
ItemB2
}
let var1: EnumA.ItemA1 = 1
let var2: number = EnumA.ItemA1
不同枚举之间不兼容:
十,类的兼容性
两个类是否兼容,仅比较结构,类似接口兼容
具有相同成员的两个类是相互兼容的:
注意:静态成员和构造函数不参与类的兼容性比较
两个类中包含相同的私有成员时,两个类不兼容,但父类和子类相互兼容
十一,泛型的兼容性
泛型类型T被接口成员使用时,才会影响泛型的兼容性
十二,泛型函数的兼容性
定义相同的两个泛型函数,如果未指定具体类型,则可相互兼容
十三,结尾
TS允许类型兼容的变量之间相互进行赋值操作,这个特性增加了语言的灵活性
结构之间兼容:成员少的兼容成员多的
函数之间兼容:参数多的兼容参数少的