wordpress情侣网站源码,微信开放平台官网登录,绍兴企业网站开发,长沙做网站微联讯点很好子类型关系 1、概念1.1 里氏替换原则1.2 自反性1.3 传递性 2、顶端类型 和 尾端类型3、字面量类型4、undefined 和 null5、枚举类型6、函数类型6.1 变型6.1.1 协变6.1.2 逆变6.1.3 双变 6.2 函数类型间的子类型关系6.2.1 函数参数数量6.2.2 函数参数类型A、非严格函数类型检查B… 子类型关系 1、概念1.1 里氏替换原则1.2 自反性1.3 传递性 2、顶端类型 和 尾端类型3、字面量类型4、undefined 和 null5、枚举类型6、函数类型6.1 变型6.1.1 协变6.1.2 逆变6.1.3 双变 6.2 函数类型间的子类型关系6.2.1 函数参数数量6.2.2 函数参数类型A、非严格函数类型检查B、严格函数类型检查 6.2.3 函数返回值类型6.2.4 函数重载 7、对象类型7.1 属性成员类型7.2 调用签名 和 构造签名7.3 字符串索引签名 和 数值型索引签名 8、类类型9、泛型类型9.1 泛型对象类型9.2 泛型函数类型9.2.1 非严格泛型函数类型检查9.2.2 严格泛型函数类型检查 10、联合类型 和 交叉类型10.1 联合类型10.2 交叉类型 1、概念
1.1 里氏替换原则
程序中任何使用了超类型 的地方都可以用其 子类型 进行替换并且在替换后程序的行为保持不变。
1.2 自反性
任意类型都是其 自身 的子类型和超类型。
1.3 传递性
若 类型A 是 类型B 的子类型且 类型B 是 类型C 的子类型那么 类型A 也是 类型C 的子类型。
2、顶端类型 和 尾端类型
顶端类型是一种通用超类型所有类型都是顶端类型的子类型同时尾端类型是所有类型的子类型。
TS 中存在两种顶端类型即any类型和unknown类型。因此所有类型都是any类型和unknown类型的子类型。
3、字面量类型
字面量类型是其对应的基础原始类型的子类型。
例如maintainer 类型是 name 类型的子类型
type maintainer Bob;
type name string;4、undefined 和 null
Undefined类型是 除尾端类型 never 外 所有类型的子类型其中也包括null类型。 Null类型是 除尾端类型和undefined类型外 的所有类型的子类型。
5、枚举类型
在联合枚举类型中每个枚举成员都能够表示一种类型同时联合枚举成员类型是联合枚举类型的子类型。 什么是联合枚举类型 枚举成员类型都是字面量类型的枚举类型。 6、函数类型
函数类型由 参数类型 和 返回值类型 构成。在比较两个函数类型间的子类型关系时要同时考虑 参数类型 和 返回值类型。
6.1 变型
在学习函数类型的字类型和超类型之间的关系前我们要先了解一个和函数类型关系非常紧密的概念——变型。
所谓变型就是描述的是复杂类型的组成类型是如何影响复杂类型间的子类型关系的。
现约定如果复杂类型 Complex 是由 类型T 构成那么我们将其记作 Complex(T)。
6.1.1 协变
假设有两个复杂类型 Complex(A) 和 Complex(B) 如果由A是B的子类型能够得出 Complex(A) 是 Complex(B) 的子类型那么我们将这种变型称作协变。
协变关系维持了复杂类型与其组成类型间的子类型关系。
6.1.2 逆变
如果由A是B的子类型能够得出 Complex(B) 是 Complex(A) 的子类型那么我们将这种变型称作逆变。
6.1.3 双变
如果由 A 是 B 的子类型或者 B 是 A 的子类型能够得出 Complex(A) 是 Complex(B) 的子类型那么我们将这种变型称作双变。
双变同时具有协变关系与逆变关系。
6.2 函数类型间的子类型关系
6.2.1 函数参数数量
子类型的 必选参数 的个数 不能多于 父类型 中的参数个数。
若函数类型 S 是函数类型 T 的子类型则 S 中的每一个必选参数必须能够在T中找到对应的参数。
当T中存在 可选参数 或 剩余参数 时函数类型检查是不可靠的。因为当使用子类型 S 替换了超类型 T 之后调用 S 时的实际参数个数可能少于必选参数的个数。例如有如下的函数s 和函数t 其中 s 是 t 的子类型使用一个实际参数调用函数 t 没有问题但是将 t 替换为其子类型 s 后会产生错误因为调用 s 需要两个实际参数。
function s(a: number, b: number): void {}
function t(...x:number[]): void {}t(0);
s(0); // 编译错误6.2.2 函数参数类型
函数的参数类型会影响函数类型间的子类型关系。
A、非严格函数类型检查
在该模式下函数参数类型与函数类型是 双变 关系。
若函数类型 S 是函数类型 T 的子类型那么 S 的参数类型必须是 T 中对应参数类型的【子类型】或者【超类型】。这意味着在对应位置上的两个参数只要存在子类型关系即可而不强调哪一方应该是另一方的子类型。
type S (a: 0 | 1) void;
type T (x: number) void;此例中S 是 T 的子类型同时 T 也是 S 的子类型。
B、严格函数类型检查
strictFunctionTypes 编译选项用来启用严格的函数类型检查。
在该模式下函数参数类型与函数类型是 逆变 关系而非相对宽松的双变关系。
若函数类型 S 是函数类型 T 的子类型那么 S 的参数类型必须是 T 中对应参数类型的 超类型。
6.2.3 函数返回值类型
在确定函数类型间的子类型关系时编译器将检查函数返回值类型 是否兼容 。
不论是否启用了strictFunctionTypes 编译选项函数返回值类型与函数类型始终是 协变 关系。
若函数类型 S 是函数类型 T 的子类型那么 S 的返回值类型必须是 T 的返回值类型的 子类型。 我理解无论是函数返回值类型还是严格模式下的函数参数类型检查都要满足赋值兼容性才符合里氏替换原则。 对于严格模式下的参数类型超类型函数的实参要能赋值给子类型的形参。 对于函数返回值类型子类型函数的返回值要能赋值给超类型函数的返回值。 6.2.4 函数重载
在确定函数类型间的子类型关系时编译器将检查函数重载签名类型是否兼容。
若函数类型 S 是函数类型 T 的子类型并且 T 存在函数重载那么 T 的每一个函数重载必须能够在 S 的函数重载中找到与其对应的子类型。
7、对象类型
在比较对象类型的子类型关系时要分别考虑 每一个 类型成员。
在结构化子类型系统中仅通过比较两个对象类型的 类型成员列表 就能够确定它们的子类型关系。对象类型的名称完全不影响对象类型间的子类型关系。
例如以下示例中 类型 A 和 类型 B 是相同类型类型 C 是 类型 A 和 类型 B 的超类型。
type A {name: string,age: number
}
type B {name: string,age: number
}
type C {name: string
}对象类型的子类型关系要满足以下条件
在数量上超类型对象类型的成员数量不能多于 子类型对象类型的成员数量。在属性成员的可访问性上超类型中的必选属性在子类型中也必须是必选属性。在成员类型上子类型的成员类型是超类型中对应的成员类型的子类型。
7.1 属性成员类型
超类型的每个属性成员 M 都能够在子类型中找到同名属性成员 N且 N 是 M 的子类型。
7.2 调用签名 和 构造签名
超类型中的调用签名 M 都能够在子类型中找到对应的调用签名 N且 N 是 M 的子类型。
对象类型中的构造签名与调用签名有着相同的判断规则。
7.3 字符串索引签名 和 数值型索引签名
父类型中有索引签名子类型中也要有并子类型的索引签名类型是父类型索引签名类型的子类型。
8、类类型
在确定两个类类型之间的子类型关系时仅检查类的 实例成员 类型类的 静态成员类型 以及 构造函数类型 不进行检查。
如果类中存在 私有成员 或 受保护成员那么在确定类类型间的子类型关系时要求私有成员和受保护成员 来自同一个类这意味着两个类需要存在 继承关系。
例如以下代码中Point 和 Position 中的受保护成员 x 都来自Point因此 Position 是 Point 的子类型。
class Point {protected x: number 0;
}
class position extends Point {protected y: number 0;
}9、泛型类型
9.1 泛型对象类型
对于泛型接口、泛型类和表示对象类型的泛型类型别名而言实例化泛型类型时使用的实际类型参数 不影响 子类型关系真正影响子类型关系的是泛型实例化后的 结果对象类型。
9.2 泛型函数类型
TS编译器提供了noStrictGenericChecks 编译选项用来启用或关闭严格泛型函数类型检查。
9.2.1 非严格泛型函数类型检查
编译器先将所有的泛型类型参数替换为 any 类型然后再确定子类型关系。这意味着泛型类型参数不影响泛型函数的子类型关系。
type A T, U(x: T, y: U) [T, U];
type B S(x: S, y: S) [S, S];将所有的类型参数替换为any类型结果如下
type A (x: any, y: any) [any, any];
type B (x: any, y: any) [any, any];9.2.2 严格泛型函数类型检查
先通过类型推断来 统一 两个泛型函数的类型参数然后再确定两者的子类型关系。
type A T, U(x: T, y: U) [T, U];
type B S(x: S, y: S) [S, S];如果我们想要确定 A 是否为 B 的子类型那么先尝试使用 B 的类型来推断A的类型。通过比较每个参数类型和返回值类型能够得出类型参数 T 和 U 均为 S。接下来使用推断的结果来实例化 A 类型即将类型 A 中的 T 和 U 均替换为 S替换后的结果如下
type A S(x: S, y: S) [S, S];
type B S(x: S, y: S) [S, S];在统一了类型参数之后再来比较泛型函数间的子类型关系。因为统一后的类型 A 和 B 相同所以 A 是 B 的子类型。
如果我们最开始想要确定 B 是否为 A 的子类型那么这时将由 A 向 B 来推断并统一类型参数的值。经推断S 的类型为联合类型“T | U”然后使用“S T | U”来实例化 B 类型结果如下
type A T, U(x: T, y: U) [T, U];
type B T, U(x: T | U, y: T | U) [T | U, T | U];此时B 不是 A 的子类型因为 B 的返回值类型不是 A 的返回值类型的子类型。
10、联合类型 和 交叉类型
10.1 联合类型
联合类型由若干成员类型构成在计算联合类型的子类型关系时需要考虑每一个成员类型。
假设有联合类型 S S0 | S1 和任意类型 T如果成员类型 S0 是类型 T 的子类型并且成员类型 S1 是类型 T 的子类型那么联合类型 S 是类型 T 的子类型。例如有如下定义的联合类型 S 和类型 T 。
type S 0 | 1;
type T number;此例中联合类型 S 是类型 T 的子类型。
假设有联合类型 S S0 | S1 和任意类型 T如果类型 T 是成员类型 S0 的子类型或者类型T是成员类型 S1 的子类型那么类型 T 是联合类型 S 的子类型。例如有如下定义的联合类型 S 和类型 T
type S number | string;
type T 0;此例中类型T是联合类型S的子类型。
10.2 交叉类型
交叉类型由若干成员类型构成在计算交叉类型的子类型关系时需要考虑每一个成员类型。
假设有交叉类型 S S0 S1 和任意类型 T如果成员类型 S0 是类型 T 的子类型或者成员类型 S1 是类型 T 的子类型那么交叉类型 S 是类型 T 的子类型。
type S { x: number } { y: number };
type T { x: number };假设有交叉类型 S S0 S1 和任意类型 T如果类型 T 是成员类型 S0 的子类型并且类型 T 是成员类型 S1 的子类型那么类型 T 是交叉类型 S 的子类型。
type S { x: number } { y: number };
type T { x: number; y: number; z: number };