一:浅议
引文---
在基于名义类型的类型系统中,数据类型的兼容性或等价性是通过明确的声明和/或类型的名称来决定的
例如在Java中的定义 String string = 'java',我们必须给string显式的生命是String类型的,在TS中,所有的数据类型基本都是结构类型,我们通过new操作符构造出来的数据,都会根据其结构成员来分析出其结构类型;
例如:
class Animal {
feet: number;
constructor(name: string, numFeet: number) { }
}
class Dog {
feet: number;
constructor(numFeet: number) { }
}
let a: Animal;
let s: Dog;
a = s; // OK
s = a; // OK
这里我们可以看出Dog和Animal两个类具有相同的成员属性,因此,基于结构类型系统的TS会检查成功;人为a和s是两种可以互相兼容的数据类型;但在Java中,
class Animal {
Number feet = 0;
}
class Dog {
Number feet = 0;
}
class Test {
public static void main() {
a = new Animal(); // Error a cannot be resolved to a variable
b = new Dog() // Error b cannot be resolved to a variable
}
}
二 类型兼容性
对于原始类型和简单的对象数据类型,兼容性是很好判断的,但是对于函数来说,就会复杂一点,包括
- 函数参数的不确定性
引用一个例子
let x = (a: number) => 0;
let y = (b: number, s: string) => 0;
y = x; // OK
x = y; // Error
由于参数的不确定性,在x和y的互相赋值操作出现了不同的情况,TS检查系统在检测函数x判定其有为number类型a的参数类型,函数x为具有b和s两个参数;当x赋值给y的时候,右边的x的参数列表能够在y中找到,并且由于js函数参数长度的不确定性,第二个参数忽略,所以能够赋值成功,当y赋值x的时候,y明确第二个参数为string类型的,而x中没有声明第二个参数的类型,所以赋值错误。
- 2.枚举
枚举类型与数字类型兼容,并且数字类型与枚举类型兼容。但是不同枚举类型之间是不兼容的
- 3.类的静态和实例、私有属性
类在声明的时候,即产生了类的本省,也声明了类的实例部分,实例可以用来做类型。 因为类可以创建出类型,所以你能够在允许使用接口的地方使用类。
所以比较两个类类型的对象时,只有实例的成员会被比较。 静态成员和构造函数不在比较的范围内。
此外类的私有成员和受保护成员会影响兼容性。 当检查类实例的兼容时,如果目标类型包含一个私有成员,那么源类型必须包含来自同一个类的这个私有成员。简而言之,不同的类中,只要含有私有或者受保护的成员,就不能单单通过结构类型去判断。即使成员完全一致,但只要没有继承关系,就会影响兼容性。
class Animal {
feet: number;
private test: any;
constructor(name: string, numFeet: number) { }
}
class Dog {
private sex: any;
feet: number;
constructor(numFeet: number) { }
}
let a: Animal;
let s: Dog;
a = s; // Property 'test' is missing in type 'Dog' but required in type 'Animal'.
s = a; // Property 'sex' is missing in type 'Animal' but required in type 'Dog'.
- 4.泛型
对于没指定泛型类型的泛型参数时,并且对结构成员的类型没有影响时,会把所有泛型参数当成any
比较。 然后用结果类型进行比较,就像上面第一个例子。
当泛型的泛型参数影响到了结构内部的成员,则会产生不同的兼容性问题。