前几天写的东西莫名奇妙报错了,发现是类型检查的问题.所以抽空总结了一下函数类型的坑. 下面是自己的理解(具体的各种复杂理论咱也不说了, 来吧, 展示~):
协变:类型收敛
逆变:类型发散
场景:
type Color = {}
type Red = {
red: any
}
let useC: (c: Color) => number
let useR: (r: Red) => number
useR = useC
useC = useR // 不报错?? 不安全 useR里是以Red类型执行的,但useC传入了Color类型
type Color = {}
type Red = {
red: any
}
let c: Color
let r: Red
// 变量类型是协变的
c = r // Red类型收敛为Color类型
r = c // 报错
// 函数参数类型是逆变的
let useC: (c: Color) => number
let useR = (r: Red) => 0
useC = useR // 协变,类型收敛。开启strictFunctionTypes:true后将报错,变为逆变。
// useC执行传入Color类型,执行的是useR,Color发散为Red类型,发生错误。
useR = useC // 逆变,类型发散。
// useR执行传入Red类型,执行的是useC,Red类型收敛为Color类型。
// 函数返回值类型是协变的
let useC2: () => Color
let useR2: () => Red
useC2 = useR2
useR2 = useC2 // 报错
总结:
除了函数参数类型是逆变,都是协变。 将一个函数赋给另一个函数变量时,要保证参数类型发散,即比目标类型范围小。 目标函数执行时是执行的原函数,传入的参数类型会收敛为原函数参数类型。
协变表示类型收敛,即类型范围缩小或不变。逆变反之。
本质是执行时类型收敛是安全的。