メインコンテンツに移動

深度サブタイピング

2 つの クラス があり、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.dokyumento.jp/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 インスタンスとしてアノテーションされている employee.who の値も変更されます。

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プロパティが共変であることを示します。共変プロパティを使用すると、そのプロパティにサブタイプ互換値を持つオブジェクトを使用できます。デフォルトでは、オブジェクトのプロパティは不変であり、読み取りと書き込みの両方が許可されますが、受け入れる値はより制限されます。

プロパティの分散の詳細はこちら。