加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
18_ 函数类型:协变与逆变_3、逆变.ts 2.25 KB
一键复制 编辑 原始数据 按行查看 历史
韩旭明 提交于 2023-01-27 16:33 . 修改目录
/**
* 逆变:
* 当 ‘函数作为参数’ 时,情况就变了
*/
class Animal {
doAnimalThing(): void {
console.log("I am a Animal!")
}
}
class Dog extends Animal {
doDogThing(): void {
console.log("I am a Dog!")
}
}
class Cat extends Animal {
doCatThing(): void {
console.log("I am a Cat!")
}
}
/**
* 不支持协变的情况,那就是 ‘函数作为参数’ 时
*
* 因为【调用方是 doAnimalThingAction(new Cat())】,这里可以传Animal的子类(协变),cat。
* 而【定义方 doDogThing函数的参数 却是Dog类型】,如果能成功,那么 cat 就做了 doDogThing 了,显然类型就不安全了 。
*/
function MakeItDoSomething(doAnimalThingAction: (ani: Animal) => void) {
//调用方
doAnimalThingAction(new Cat())
}
//定义方
function doDogThing(dog: Dog){
dog.doDogThing()
}
//以下代码会报错
MakeItDoSomething(doDogThing)
//下面的代码同理:
function MakeItDoSomethingA(ani: Animal){}
const fn: typeof MakeItDoSomethingA = doDogThing
/**
* 逆变:
* 为了保证【调用方】传入的参数类型拥有的属性和方法 一定 大于等于 【定义方】定义参数类型拥有的属性和方法。
* 所以这里【doDogThing函数的参数的类型】,也就是dog的类型,一定要是Animal 类型或者Animal的父类,要确保拥有的属性和方法尽可能的少。
* 父类(Object)赋值给子类(Animal)的情况,就是逆变。
*/
// 定义方
function doDogThing1(dog: Object){
dog.toString()
}
function doDogThing2(dog: Animal){
dog.doAnimalThing()
}
// 不报错了。
MakeItDoSomething(doDogThing1)
MakeItDoSomething(doDogThing2)
// 不报错了。
function doAnimalThingAction(ani: Animal){}
type AniFuncType = typeof doAnimalThingAction
const fn1: AniFuncType = doDogThing1
const fn2: AniFuncType = doDogThing2
/**
* 最后来总结一下:
* 不管是协变还是逆变,都是为了达到一个目的,
* 那就是【增加调用方参数类型拥有的属性和方法数量】,或者【减少定义方参数拥有的属性和数量】,来保证类型安全。
* 函数类型的赋值,要考虑逆变的情况。
*/
//export {}:解决“无法重新声明块范围变量”错误提示问题
export { }
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化