类型比较
TypeScript 使用的是结构性类型系统。当我们比较两种不同的类型时,并不在乎它们从何处而来,如果所有成员的类型都是兼容的,我们就认为它们的类型是兼容的。
然而,当我们比较带有 private 或 protected 成员的类型的时候,情况就不同了。 如果其中一个类型里包含一个 private 成员,那么只有当另外一个类型中也存在这样一个 private 成员,并且它们都是来自同一处声明时,我们才认为这两个类型是兼容的。对于 protected 成员也使用这个规则。
比如以下两种类型认为是兼容的:
class A {
public name: string;
}
class B {
public name: string;
}
const test: A = new B();
但是如果带有 private 成员,情况就不一样了:
class A {
public name: string;
private age: number;
}
class B {
public name: string;
private age: number;
}
// fail:
// Type 'B' is not assignable to type 'A'.
// Types have separate declarations of a private property 'age'.
const test: A = new B();
但是如果 private 类型来自于同一处声明,那么类型又会变成兼容的了:
class Base {
private age: number;
}
class A extends Base {
public name: string;
}
class B extends Base {
public name: string;
}
const test: A = new B();
而下面的例子是不兼容的:
class Base {
private age: number;
}
class A extends Base {
public name: string;
}
class B extends Base {
public name: string;
private age: number;
}
// fail:
// Type 'B' is not assignable to type 'A'.
// Types have separate declarations of a private property 'age'.
const test: A = new B();
对于 protected 成员,下面这种情况是兼容的:
class Base {
protected age: number;
}
class A extends Base {
public name: string;
}
class B extends Base {
public name: string;
protected age: number;
}
const test: A = new B();
注意理解什么是同一处声明:子类中的私有成员跟父类中的私有成员没有半点关系,在子类中,对父类的私有成员既不能访问又不能覆盖;而受保护成员就相反了。
所以上述例子中, B 类中的受保护成员 age
,实际上和 Base 类中的 age
指向的是同一个数据成员,而更前面的例子中, B 类中私有成员 age
和 Base 类中的私有成员 age
是完全两个成员变量,所以 A 和 B 是不兼容的。
参数属性
TypeScript 中也可以在构造函数的参数里面声明成员变量:
class Animal {
constructor(private name: string) { }
}
// 等同于
class Animal {
private name: string;
constructor(name: string) {
this.name = name;
}
}