1. 子类型
1.1. 在期望类型T的实例的任何地方,都可以安全地使用类型S的实例,则类型S是类型T的子类型
1.1.1. 里氏替换原则(Liskov substitution principle)
2. 名义子类型
2.1. 明确指定
2.2. 显式声明一个类型是另一个类型的子类型
2.3. 大部分主流编程语言采用的方式
2.3.1. Java
2.3.2. C#
2.4. TypeScript通过使用unique symbol可以模拟名义子类型
3. 结构子类型
3.1. 类型具有相同的结构
3.2. 不需要显式声明子类型关系
3.3. 一个类型的结构与另一个类型相似(具有相同的成员,可能还有额外的成员),自动被视为后者的子类型
3.4. TypeScript使用结构子类型
3.5. 即使类型不在我们的控制范围内,我们在类型之间仍然能建立关系
3.5.1. 例如:我们不能修改的来自外部库的一个类型
4. 极端情况
4.1. 顶层类型
4.1.1. 把任何东西赋值给它的类型
4.1.1.1. 用来存储任何东西
4.1.1.2. C#的Object
4.1.1.3. TypeScript的unknown
4.1.1.3.1. null的类型是null
4.1.1.3.2. undefined的类型是undefined
4.1.1.3.3. Object
4.1.1.3.4. 三者和类型即unknown
4.1.1.3.4.1. Object | null |undefined
4.1.1.3.5. 只有当我们确认一个值具有某个类型时,才能把该值用作该类型
4.1.1.3.5.1. C#提供了is关键字
4.1.1.3.5.2. Java则提供了instanceof
4.1.2. 其他任何类型的父类型
4.1.3. 位于子类型层次结构的顶端
4.2. 底层类型
4.2.1. 可以赋值给任何东西的类型
4.2.1.1. 没有某种类型的实例可用
4.2.1.2. TypeScript的never
4.2.2. 其他任何类型的子类型
4.2.3. 位于子类型层次结构的底端
4.2.4. 始终是一个空类型:这是我们不能为其创建实际值的类型
4.2.5. 允许我们假装有任何类型的一个值,即使我们并不能生成这个值
4.2.6. 很少有主流语言提供底层类型
4.2.6.1. 使一个类型成为空类型,但不能使其成为底层类型
4.2.6.2. 除非在编译器中实现,否则我们无法自定义底层类型
5. 和类型
5.1. 父类型比子类型的类型更多
5.1.1. 例如:Triangle | Square是Triangle | Square | Circle的子类型
5.2. Variant能够封装几个类型中某个类型的值,但是它本身不是其中任何一个类型
6. 可变性
6.1. 协变性
6.1.1. 一个类型保留其底层类型的子类型关系
6.1.2. 数组具有协变性,因为它保留了子类型关系
6.1.3. 当处理集合(如LinkedList)时,不同的语言具有不同的行为
6.1.3.1. 在C#中,必须通过声明接口并使用out关键字(ILinkedList),显式指出一个类型(如LinkedList)的协变
6.1.4. 函数的返回类型具有协变性
6.2. 逆变性
6.2.1. 一个类型颠倒了其底层类型的子类型关系
6.2.2. 大部分编程语言中,函数的实参是逆变的
6.2.2.1. TypeScript是一个例外
6.2.2.1.1. 故意做出的设计决策
6.3. 双变性
6.3.1. 类型的底层类型的子类型关系决定了它们互为子类型
6.3.2. 在TypeScript中函数实参的双变性可能导致错误的代码通过编译
6.4. 不变性
6.4.1. 一个类型不考虑其底层类型的子类型关系
6.4.2. C#中的List具有不变性
7. any类型
7.1. 可以把任何值赋值给any
7.2. 可以把any值绕过类型检查赋值给其他任何类型
7.3. 会绕过类型检查立即把该值用作其他任何类型的值
posted @
2023-01-14 14:32
躺柒
阅读(
62)
评论()
编辑
收藏
举报