深度子类型
假设我们有两个 类,它们使用 extends
具有子类型关系
1class Person {2 name: string;3}4class Employee extends Person {5 department: string;6}
在需要 Person
实例的地方使用 Employee
实例是有效的。
1class Person { name: string }2class Employee extends Person { department: string }3
4const employee: Employee = new Employee();5const person: Person = employee; // OK
但是,在需要包含 Person
实例的对象的地方使用包含 Employee
实例的对象是无效的。
1class Person { name: string }2class Employee extends Person { department: string }3
4const employee: {who: Employee} = {who: new Employee()};5const person: {who: Person} = employee; // Error
5:31-5:38: Cannot assign `employee` to `person` because `Person` [1] is incompatible with `Employee` [2] in property `who`. This property is invariantly typed. See https://flow.node.org.cn/en/docs/faq/#why-cant-i-pass-a-string-to-a-function-that-takes-a-string-number. [incompatible-type]
这是一个错误,因为对象是可变的。employee
变量引用的值与 person
变量引用的值相同。
person.who = new Person();
如果我们写入 person
对象的 who
属性,我们也改变了 employee.who
的值,它被明确地注释为 Employee
实例。
如果我们阻止任何代码通过 person
变量写入新值到对象,那么使用 employee
变量将是安全的。Flow 提供了用于此的语法
1class Person { name: string }2class Employee extends Person { department: string }3
4const employee: {who: Employee} = {who: new Employee()};5const person: {+who: Person} = employee; // OK6person.who = new Person(); // Error!
6:8-6:10: Cannot assign `new Person()` to `person.who` because property `who` is not writable. [cannot-write]
加号 +
表示 who
属性是 协变 的。使用协变属性允许我们使用对该属性具有子类型兼容值的那些对象。默认情况下,对象属性是不可变的,它们允许读写,但在它们接受的值方面更严格。
阅读更多关于 属性变异 的内容。