• home > webfront > ECMAS > typescript >

    从java的角度看typescript的subtyping与inheritance的区别

    Author:zhoulujun Date:

    之前我觉得对subtyping与inheritance理解的差不多了,但是看了知乎推荐的这个回答subtyping和inheritance的区别是什么? - Sayako Hoshi

    之前我觉得对subtyping与inheritance理解的差不多了,但是看了知乎推荐的这个回答 

    subtyping和inheritance的区别是什么? - Sayako Hoshimiya的回答 - 知乎

    https://www.zhihu.com/question/57486254/answer/153071178

    然后还是觉得深究一下。其实google一下,找到的细说这个两个概念的中文文章还是比较少的

    我比较认可的回答是:

    Inheritance IS NOT

    Inheritance IS Subtyping

    我的看法是,这俩是不同领域的术语,没必要硬扯到一起,在具体场景下可能相关也可能不相关。

    比如像 Java/C++ 之类的基于 class 的面象对象语言,inheritance 必然也定义了一个子类型;

    而象 ES6 之前的 JavaScript,基于属性拷贝(如_.extend())的 inheritance 是直接在对象实例之间完成的,并不涉及类型定义,而基于原型链的(包括 ES6 的 class)就可以视为 subtyping 了

    链接:https://www.zhihu.com/question/57486254/answer/15308022

    对比java与typescript来讲,这个是一贯风格

    Subtyping in TypeScript

    先看这篇:Subtyping in TypeScript https://juejin.cn/post/6959498972268822542

    再看这篇: 理解TypeScript中“类型”的概念到底有多难? https://www.tangshuang.net/8140.html

    子类型是一个庞大的话题,涉及到抽象概念、(推导)规则、协变、逆变等等,你可以阅读这篇文章深入了解,本文只会聊其中很小的一部分。子类型揭示了TS类型系统的核心实质,它是一个推导系统,推导即基于某些定理、公理、定律进行演算的过程(在TS中主要是基于内建的一些规则用于检查值的类型)。

    TS的类型基于“集合”的概念

    一个类型,代表一个集合。例如string类型代表的是所有字符串的集合。

    在检查过程中,如何决定一个值属于这个“集合”呢?它的依据在于这个值的“形状(Shape)”。

    怎么定义值的形状呢?

    它由两部分组成,一部分是基于JS的基础类型,得到该值的数据类型,另一部分是基于TS的另外一个核心Structural(结构化的),得到该值的结构。基于数据类型和结构这两个概念,TS获得值的形状,基于“推导”的运行方式,决定该值是否符合某个类型。

    正是这样,那么下面两个类型,在TS里面,竟然是“相等”的(仅类型相等,A === B为false):

    class A {
      name: string;
    }
    
    class B {
      name: string;
    }

    在Java或C#这样的语言中,完全不能被理解,它俩怎么可能相等?而在TS中,它们代表着形状为 { name: string } 的对象(JS中一切复合类型皆是对象)的集合。

    一个值,在TS中,它和集合的对应关系不是一对一的,它可以同时属于多个集合中,是一对多的关系。而同时,两个不同的集合,却可能表达相同的形状。如果你看它像鸭子,那么它就是鸭子。于是,A和B相等了,只是取了不同的名字而已,就像一个人在这个杂志上叫鲁迅,在另一个杂志上叫润土。

    TS是怎么对待(treat)这些集合的呢?它基于一种推导的范式确定两个集合之间的关系。两个集合存在什么关系呢?只存在两种关系:

    一种是A是B的子类型,另一种是A不是B的子类型。(A和B可交换位置)子类型,是TS对待类型集合的唯一方式。在TS中,所有类型的总和,都处在子类型体系中,这个子类型体系是一个树状网络,它的根是一个叫unknow的类型,而它的底是一个叫never的类型(never是所有类型的子类型,是树状的所有叶子)。

    子类型用于表达类型与类型的二元关系,当一个值的类型属于某一类型时,它同时属于该类型的父类型。它的产生方式又有多种,

    • 基于父类型扩展,也就是使用extends

    • 基于一种叫交叉(A & B)的操作得到

    • 基于一种叫联合(A | B)的操作得到

    曾经有这样一个预言,让一只猴子坐在一台电脑前敲击键盘,总有一天它能敲出莎士比亚的所有著作(猴子不懂艺术)。同样的道理,只要给定条件,你永远可以在TS的子类型体系中找到对应的类型,而这个过程基于“推导”完成。因此,实际上,子类型的产生方式只有一种而非三种或更多,这种方式就是基于某一类型(never除外)扩展出新类型。


    参考文章:




    转载本站文章《从java的角度看typescript的subtyping与inheritance的区别》,
    请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/typescript/2021_0831_8672.html