TypeScript Type Compatibility(类型兼容)
TypeScript中的类型兼容是基于结构归类的。在普通分类的相比之下,结构归类是一种纯粹用于将其成员的类型进行关联的方法。思考下面的代码:
interface Named {
name: string;
}
class Person {
name: string;
}
var p: Named;
// 正确, 因为这里编译器自动进行结构归类
p = new Person();
如C#、Java这些表面上的类型语言(这里指的“表面上的类型语言”,指C#和Java需要使用“implements”关键字明确指出类实现某个接口才能对应得上其类型),以上的代码便会被当作错误的,因为没有明确指出Person类实现(implements)Named接口。
TypeScript的结构类型系统就是基于JavaScript代码典型的写法设计的。因为JavaScript广泛使用匿名对象如函数表达式和字面量对象,使用结构类型系统代替表面上处理将使JavaScript中这些关系体现的更自然。
TypeScript类型系统允许执行某些在编译阶段无法确定安全性的操作。当一个类型系统有这个属性的时候,我们视之为“不健全的”。TypeScript中允许执行这些操作这一机制是经过仔细考虑的,通过文档我们将解释什么情况下会发生这种事和允许这些操作后所带来的好的一面。
跟着代码出发(老司机,带带我...)
TypeScript结构类型系统的基本规则如:如果x是兼容y的,那么y至少具有和x相同的属性成员。例如:
interface Named {
name: string;
}
var x: Named;
// 推断出y的类似是{ name: string; location: string; }
var y = { name: 'Alice', location: 'Seattle' };
x = y;
为了检查y是否能够赋值给x,编译器需要检查x的每个属性,并且在y中找到对应的兼容属性。在这种情况下,y必须有个名为name并且值是字符串的属性。而y满足了这条件,所以能够赋值给x。
同样的规则也适用在检查函数调用参数时:
// 接着上面的代码
function greet(n: Named) {
alert('Hello, ' + n.name);
}
greet(y); // ok
注意,y有一个额外的"location'属性,但这并未产生错误。只有目标类型的成员(这里的目标类型指“Named”)会被检查是否兼容。
比较的过程是递归进行的,检查每个成员及其子成员的类型。
两个函数之间的比较
原始类型和对象类型的比较是相对简单的,但问题是被认为是兼容的函数是怎么样的呢。让我们从一个最基本的例子开始吧,以下两个函数的不同之处仅仅在于他们的参数列表:
var x = (a: number) => 0;
var y = (b: number, s: string) => 0; y = x; // ok
x = y; // 错误
若要检查x是否可以赋值给y,首先看参数列表。y中的每个参数必须在x中都有相应并且类型兼容的参数。主意,参数名可不考虑,只要类型能够对应上。在这个案例中,x的每个参数在y中都有相应的参数,所以是允许赋值的。第二个赋值是错误的,因为y的第二个属性是必须的,但是x没这个属性,所以不被允许赋值。
你可能对为什么在y=x中允许第二个参数而感到疑惑。赋值的过程允许忽略函数额外的参数,这在JavaScript中实际上很常见。例如Array的forEach函数为他的回调函数提供了三个参数:数组元素、索引、包含它的数列。然而,大多用到的也就第一个参数。
var items = [1, 2, 3]; // 这些参数不是强制要求的
items.forEach((item, index, array) => console.log(item)); // 这样也可以
items.forEach((item) => console.log(item));
现在让我们来看看返回值类型是如何处理的,使用两个仅返回值类型不同的函数:
var x = () => ({name: 'Alice'});
var y = () => ({name: 'Alice', location: 'Seattle'});
x = y; // ok
y = x; // 错误,因为x()缺少一个属性
类型机制强制要求源函数的返回值类型是目标函数返回值类型的子类型。
可选参数及剩余参数
当对函数的兼容进行比较时,可选和必须的参数是可以互换的。源类型有额外的可选参数不会造成错误,目标类型的可选参数中不存在对应参数也不会产生错误。
当函数有其余的参数,将会被当作无限的可选参数一样来处理。
从类型机制来看这是不健全的,但从代码运行的角度看,可选参数不是强制要求的,因为它相当于在函数参数的对应位置传入一个"undefined"。
下面的例子是个普遍模式的函数,该函数需要传入个回调函数,并且在调用的时候传入可预知(对于开发者而言)但是未知数量(对于类型机制)的参数。
function invokeLater(args: any[], callback: (...args: any[]) => void):void {
callback.apply(null,args);
}
// invokeLater"可能"任何数量的参数
invokeLater([1, 2], (x, y) => console.log(x , y));
invokeLater([3], (x?, y?) => console.log(x , y));
invokeLater([4,5,6,7], (x?, y?) => console.log(x , y));
重载的函数
当一个函数具有重载情况时,源类型的每次重载必须在目标类型上可找到匹配的签名。这确保了目标函数可以在所有源函数可调用的地方调用。当做兼容性检查时,带有特殊签名的函数重载(那些重载时使用字符串)将不会使用他们特殊签名。(详情可见:TypeScript Declaration Merging(声明合并)中的接口合并第二个案例)
枚举
枚举和number相互兼容。不同枚举类型的枚举值之间是不兼容的。例如:
enum Status { Ready, Waiting };
enum Color { Red, Blue, Green };
var status = Status.Ready;
status = Color.Green; // 错误
类
类的兼容和对象字面量类型还有接口的兼容相似,只是有一个不同:它具有静态类型和实例类型。比较两个类类型的对象时,只比较实例部分的成员。静态部分的成员和构造函数不影响兼容性。
class Animal {
feet: number;
constructor(name: string, numFeet: number) { }
}
class Size {
feet: number;
constructor(numFeet: number) { }
}
var a: Animal;
var s: Size;
a = s; // ok
s = a; // ok
类的私有成员
类中的私有成员会影响其兼容性。当一个类的实例进行兼容性检查时,如果它包含一个私有成员,那么目标类型必须也包含一个来源与同一个类的私有成员(详情可参阅:TypeScript Class(类)中的理解Private(私有))。这也造成了一个类可以被赋值为其父类的实例,但是却不能被赋值成另一个继承其父类的类(虽然他们是同一个类型)。
泛型
因为TypeScript是一个结构类型系统,参数类型只影响将其作为部分成员类型的目标类型(比如有个函数fn(a:string),然后函数中有个变量的某属性值是a,那么a对这个目标类型将产生影响)。
案例:
interface Empty<T> {
}
var x: Empty<number>;
var y: Empty<string>;
x = y; // ok, y可以和x的结构相匹配
在上述例子中,x和y是兼容的,因为他们的结构在使用类型参数并没什么不同之处。改变这个例子,给Empty<T>加个成员,看看会是什么情况:
interface NotEmpty<T> {
data: T;
}
var x: NotEmpty<number>;
var y: NotEmpty<string>;
x = y; // 错误,x和y不兼容
对于那些没有指定其参数类型的泛型类型,兼容性的检查是通过为所有没指定参数类型的参数使用"any"代替的。然后目标类型检查兼容性,就和非泛型的案例一般。
案例:
var identity = function<T>(x: T): T {
// ...
}
var reverse = function<U>(y: U): U {
// ...
}
identity = reverse; // ok,因为(x: any)=>any和(y: any)=>any可以匹配
深层探讨
子类VS赋值
至此为止,我们了解了兼容性,它并未在语言规范里定义。在TypeScript中有两种兼容:子类和赋值。它们的不同点在于,赋值扩展了子类型的兼容性并且可对"any"进行取值和赋值、对枚举进行取对应数值。
根据情况的不同,TypeScript语言会在不同的地方使用两种兼容机制中的一种。对于实际运用而言,类型的兼容性是由赋值时的兼容检查或者implements和extends关键字来控制的。更多详情,请参照TypeScript spec (友情提醒,是doc文件下载)
TypeScript Type Compatibility(类型兼容)的更多相关文章
- TypeScript Type Innference(类型推断)
在这一节,我们将介绍TypeScript中的类型推断.我们将会讨论类型推断需要在何处用到以及如何推断. 基础 在TypeScript中,在几个没有明确指定类型注释的地方将会使用类型推断来提供类型信息. ...
- 为vue3.0学点typescript, 解读高级类型
知识点摘要 本节课主要关键词为: 自动类型推断 / 类型断言 / 类型别名(type) / 映射类型(Pick/Record等...) / 条件类型(extends) / 类型推断(infer) 自动 ...
- TypeScript 之 基础类型、高级类型
基础类型:https://m.runoob.com/manual/gitbook/TypeScript/_book/doc/handbook/Basic%20Types.html 高级类型:https ...
- TypeScript完全解读(26课时)_11.TypeScript完全解读-类型推论和兼容性
11.TypeScript完全解读-类型推论和兼容性 在一些时候省略指令,ts会帮我们推断出省略的类型的地方适合的类型,通过学习ts的类型推论了解ts的推论规则 类型兼容性就是为了适应js灵活的特点, ...
- 类型兼容原则(C++)
类型兼容原则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代. 通过公有继承,派生类得到了基类中除构造函数.析构函数之外的所有成员.这样,公有派生类实际具备了基类的所有功能,凡是基类能解 ...
- media query(媒体查询)和media type(媒体类型)
media type(媒体类型)是css 2中的一个非常有用的属性,通过media type我们可以对不同的设备指定特定的样式,从而实现更丰富的界面.media query(媒体查询)是对media ...
- 【Type】类型 ParameterizedType
Type 接口[重要] Type接口完整的定义: public interface java.lang.reflect.Type { /** * Returns a string describing ...
- 【转载】C#使用is关键字检查对象是否与给定类型兼容
在C#的编程开发过程中,很多时候涉及到数据类型的转换,如果强行转换数据类型,有时候可能会出现程序运行时错误,C#语言中提供了is关键字可以检查对象是否与给定类型兼容,可先判断类型兼容后再进行对象的转换 ...
- Type Java类型
参考:https://blog.csdn.net/a327369238/article/details/52621043 Type —— Java类型 Type是一个空接口,所有类型的公共接口(父接口 ...
随机推荐
- 开发者调试工具Chrome Workspace
Workspace是个什么样的东西呢?他能够在开发者工具中调试修改js或者css同时自动保存文件,能够避免开发人员在工具中调试好,再到编辑器中修改一次代码的重复操作,能够提高一定的效率 配置Chrom ...
- TNS-12541: TNS:no listener TNS-12560 TNS-00511: No listener
为了测试需要,系统管理员帮忙将一台ORACLE数据库服务器克隆到虚拟机上,我上去删除了root.oracle.tomcat账号下的crontab定时作业,然后启动了ORACLE数据库实例,删除 ...
- Linux下查找文件:which、whereis、locate、find 命令的区别
我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索.which 查看可执行文件的位置,通过环境变量查whereis 查看文件的位置,通过数据库查,每 ...
- 对B+树与索引在MySQL中的认识
[TOC] 概述 本质:数据库维护某种数据结构以某种方式引用(指向)数据 索引取舍原则:索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数 B树 满足的条件 d为大于1的一个正整数,称为B-Tre ...
- 【转】JVM运行原理及JVM中的Stack和Heap的实现过程
来自: http://blog.csdn.net//u011067360/article/details/46047521 Java语言写的源程序通过Java编译器,编译成与平台无关的‘字节码程序’( ...
- Linux的概念与体系
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我在这一系列文章中阐述Linux的基本概念.Linux操作系统继承自UNIX.一个 ...
- 解决虚拟机VMware安装CentOS7.0识别不到网卡
由于Vmware虚拟网卡和linux兼容问题导致驱动无法正常安装,默认的网卡类型不兼容. 解决方法 找到我们的Vmware虚拟机文件夹,将VMware 虚拟机配置 (.vmx),追加一条设置我们网卡类 ...
- [Django]网页中利用ajax实现批量导入数据功能
url.py代码: url(r'^workimport/$', 'keywork.views.import_keywork', name='import_keywork') view.py代码: fr ...
- 天河2号荣膺第41届TOP500榜首
国际TOP500组织在6月17日公布最新全球超级计算机500强榜单,由中国国防科技大学研制的“天河二号”以每秒33.86千万亿次的浮点运算速度成为全球最快的超级计算机. 天河2号(又称银河2号),将在 ...
- 解决“只能通过Chrome网上应用商店安装该程序”的方法
摘要 : 最近有些用户反映某个Chrome插件在安装的时候,提示"只能通过Chrome网上应用商店安装该程序",为了解决这一问题,Chrome插件网带来了相关的解决方法. 某些用户 ...