上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
返回列表 发新帖
楼主: 李恒道 - 

typescript 协变与逆变与双向协变

[复制链接]
  • TA的每日心情
    慵懒
    2024-10-28 07:07
  • 签到天数: 193 天

    [LV.7]常住居民III

    712

    主题

    5961

    回帖

    6760

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6760

    荣誉开发者喜迎中秋油中2周年生态建设者

    发表于 2022-6-26 17:43:59 | 显示全部楼层 | 阅读模式

    前文

    最近在学习ts
    好多乱七八糟的概念都不懂
    一之哥耐心辅导了两天才明白了一个大概概念
    记录一下

    协变

    我们可以假设一个
    class animal{
    xxxx
    }
    class dog extends animal{
    xxxx
    }
    这个时候animal是dog的父类
    如果我们将子类的实例赋值给数据类型为父类的变量
    是可以的
    这点在c++之类的也非常常见
    这个就叫协变
    let animal_ins=new dog()
    总结一句话就是
    由子类变成父类就叫协变

    逆变

    逆变是与协变相反的
    是由父类变成子类
    关于这点我们可以看一个demo
    我们假设两个函数
    图片.png
    handle_animal类型是(animal)=>void
    handle_dog的类型是(dog)=>void
    大家可以猜一下这两个相互赋值的结果
    图片.png
    结果是handle_animal可以赋值给handle_dog
    而handle_dog不可以赋值给handle_animal
    为什么?
    我们可以想一下
    我们传递给变量的是一个函数的引用
    在赋值的时候会检查两边的参数类型
    可以知道handle_animal要求传入一个animal
    而handle_dog要求传入一个dog
    animal是dog的父类
    可以知道animal其所需的数据一定可以由dog满足
    所以可以赋值
    而如果使用了
    handle_dog赋值给handle_animal
    我们的handle_animal的类型限制是animal
    函数却要求一个dog
    animal无法满足其充当dog的数据
    所以无法赋值
    总而言之
    即在一个父子继承的过程中
    所需的数据可以被满足
    即可正常赋值

    怎么看出来的逆变

    我们将handle_animal的函数赋值给handle_dog后
    虽然函数已经进行了赋值
    但是其类型依然是dog类型
    图片.png
    说明传入的参数由要求父类型变成了要求子类型
    即父类变子类
    称之为逆变
    而在函数返回类型的过程中
    可以将函数返回的子类类型赋值给父类类型变量
    因为由子类变父类
    称之为协变
    所以官方才说
    参数是逆变的
    返回是协变的

    双向协变

    在早期ts版本中
    其参数既可以逆变
    又可以协变
    即称之为双向协变
    但是在参数中协变是不安全的

    let func:(animal)=>void=function (dog:dog){dog.eat_shit()}
    在早期的版本是可以正常通过类型检查的
    但是animal的数据不足以支撑dog类型的一些特殊属性
    所以容易引发报错
    如这个demo

    enum EventType { Mouse, Keyboard }
    
    interface Event { timestamp: number; }
    interface MouseEvent extends Event { x: number; y: number }
    interface KeyEvent extends Event { keyCode: number }
    
    function listenEvent(eventType: EventType, handler: (n: Event) => void) {
        /* ... */
    }
    
    // Unsound, but useful and common
    listenEvent(EventType.Mouse, (e: MouseEvent) => console.log(e.x + ',' + e.y));
    
    // Undesirable alternatives in presence of soundness
    listenEvent(EventType.Mouse, (e: Event) => console.log((<MouseEvent>e).x + ',' + (<MouseEvent>e).y));
    listenEvent(EventType.Mouse, <(e: Event) => void>((e: MouseEvent) => console.log(e.x + ',' + e.y)));
    
    // Still disallowed (clear error). Type safety enforced for wholly incompatible types
    listenEvent(EventType.Mouse, (e: number) => console.log(e));

    图片.png
    我们可以看到
    (MouseEvent)=>void赋值给(Event)=>void失败了
    因为子类型想变化成父类型
    属于一个类型的协变
    而参数在当前版本协变已经不允许了
    所以报错

    结语

    ts好难啊...

    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
  • TA的每日心情
    开心
    2024-7-16 15:40
  • 签到天数: 276 天

    [LV.8]以坛为家I

    115

    主题

    460

    回帖

    997

    积分

    荣誉开发者

    积分
    997

    荣誉开发者油中2周年卓越贡献生态建设者油中3周年

    发表于 2022-6-26 20:16:04 | 显示全部楼层
    感觉就是强转类型呀。我也不懂协变第一次听
    接脚本定制
    I frequently record, because want to leave something.
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2024-10-28 07:07
  • 签到天数: 193 天

    [LV.7]常住居民III

    712

    主题

    5961

    回帖

    6760

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6760

    荣誉开发者喜迎中秋油中2周年生态建设者

    发表于 2022-6-26 20:57:30 | 显示全部楼层
    wwwwwllllk 发表于 2022-6-26 20:16
    感觉就是强转类型呀。我也不懂协变第一次听

    没错
    就是函数类型转换的规定~
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

  • TA的每日心情
    开心
    昨天 13:37
  • 签到天数: 213 天

    [LV.7]常住居民III

    305

    主题

    4189

    回帖

    4056

    积分

    管理员

    积分
    4056

    管理员荣誉开发者油中2周年生态建设者喜迎中秋油中3周年挑战者 lv2

    发表于 2022-6-26 22:48:02 | 显示全部楼层
    学习了,感谢楼主分享
    上不慕古,下不肖俗。为疏为懒,不敢为狂。为拙为愚,不敢为恶。
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2024-10-28 07:07
  • 签到天数: 193 天

    [LV.7]常住居民III

    712

    主题

    5961

    回帖

    6760

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6760

    荣誉开发者喜迎中秋油中2周年生态建设者

    发表于 2022-6-27 09:26:31 | 显示全部楼层
    王一之 发表于 2022-6-26 22:48
    学习了,感谢楼主分享

    mhsj教mhsj代码?
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表