类型兼容
TypeScript里的类型兼容性是基于结构类型系统的,只要二者的结构组成相同,就认为二者属于统一类型
1 | interface Pet { |
关于可靠性的注意事项
TypeScript的类型系统允许某些在编译阶段无法确认其安全性的操作。当一个类型系统具此属性时,被当做是“不可靠”的
TypeScript结构类型系统的基本规则是,如果x要兼容y,那么y至少具有与x相同的成员。可以有额外的属性存在。
比较两个函数
首先看它们的参数列表,要求类型相同
函数参数双向协变/函数协逆变
协变
当子类型包含父类型的属性时,允许子类型的变量赋值给父类型的变量,称为协变
逆变
参数为父类型的函数可以被赋值给参数为子类型的函数,称为逆变。
假如颠倒过来,就变成了类型不安全的情况。因为父类型的约束更少,范围更广,子类型的约束更多。子类型中的属性可能父类型中并没有要求
在ts2.x前支持父类型可以赋给子类型,子类型同样可以赋给父类型,称为双向协变。但因为双向协变的不安全性,ts之后加入了
strictFunctionTypes
,设置为true即可关闭双向协变的支持
默认情况下,一个函数类型中返回值类型是协变的,而参数类型是逆变的
可选参数及剩余参数
比较函数兼容性的时候,可选参数与必须参数是可互换的,即二者在类型判断上没有区别,剩余参数则是被当做无限个可选参数
从运行时角度来看,可选参数一般不强制,因为对于大部分函数来说相当于传递了一些undefinded
。
函数重载
对于有重载的函数,源函数的每个重载都要在目标函数上找到对应的函数签名
枚举
枚举类型与数字类型兼容,并且数字类型与枚举类型兼容。不同枚举类型之间是不兼容的
1 | enum Status { Ready, Waiting }; |
类
与对象字面量和接口差不多,但有一点不同:类有静态部分和实例部分的类型
比较两个类类型的对象时,只有实例的成员会被比较。 静态成员和构造函数不在比较的范围内
1 | class Animal { |
类的私有成员和受保护成员
当检查类实例的兼容时,如果目标类型包含一个私有成员,那么源类型必须包含来自同一个类的这个私有成员
这条规则也适用于包含受保护成员实例的类型检查。允许子类赋值给父类,但是不能赋值给其它有同样类型的类
泛型
类型参数只影响使用其做为类型一部分的结果类型
1 | interface Empty<T> {} |
当结果类型使用了类型参数时,比较会发生变化
1 | interface NotEmpty<T> { |