Javascript 具有深子类型的流错误

Javascript 具有深子类型的流错误,javascript,ecmascript-6,flowtype,Javascript,Ecmascript 6,Flowtype,根据flow的文档,这是可行的 // @flow type ObjectA = { foo: string }; type ObjectB = { foo: string, bar: number }; let objectB: ObjectB = { foo: 'test', bar: 42 }; let objectA: ObjectA = objectB; // Works! 但更深入地实现这一点并不重要 // @flow type ObjectA = { foo: { bar: st

根据flow的文档,这是可行的

// @flow
type ObjectA = { foo: string };
type ObjectB = { foo: string, bar: number };

let objectB: ObjectB = { foo: 'test', bar: 42 };
let objectA: ObjectA = objectB; // Works!
但更深入地实现这一点并不重要

// @flow
type ObjectA = { foo: { bar: string } };
type ObjectB = { foo: { bar: string, baz: string } };

let objectB: ObjectB = { foo: { bar: '123', baz: '456' } };
let objectA: ObjectA = objectB; // Error! Why?

知道为什么吗?

据我所知,一种可能的方法是将物体展开。如果没有此流,则无法读取属性

// @flow
type ObjectA = { foo: { bar: string } };
type ObjectB = { foo: { bar: string, baz: string } };

let objectB: ObjectB = { foo: { bar: '123', baz: '456' } };
let objectA: ObjectA = {...objectB}; // spread operator applied

在较高的级别上,您可以重用
objectB
实例,只需对ObjectA类型稍作修改,也可以创建一个新对象。让我们深入了解您的选择:

将对象特性标记为协变 您试图做的是将
ObjectB
强制转换为
ObjectA
。流抱怨的原因是
ObjectA
中的
foo
类型默认为。
ObjectB的
foo
属性是
ObjectA的
foo
属性的子类型。为了让Flow理解这一点,我们只需要将
foo
属性标记为:

()

将属性标记为“协变”基本上表示您承诺只读取该属性,而不会写入该属性。请参见,如果删除了objectA的
baz
属性,它将从objectB中删除
baz
。通过将其标记为协变,如果您向其写入,Flow将抛出错误:

()

此模式也适用于更深层次的嵌套对象:

()

有关此键入的更多详细信息,请参阅上的流程文档

使用
$ReadOnly
流有一个UTILITY类型,用于将对象的所有属性标记为协变,因此您可能希望改用它:

()


但这只会产生一个层次的深度,它会创建一个额外的对象。通常,当我需要以只读方式使用对象时,我会跳过此选项,并最终使用
$ReadOnly

我确信这只适用于一个层次的深度(从我处理此问题时开始)。如果我的回答(或其他回答)回答了您的问题,请随意将其标记为已接受的答案(并将您的问题从列表中删除)“未回答的”一桶问题)
// @flow
type ObjectA = { +foo: { bar: string } };
type ObjectB = { foo: { bar: string, baz: string } };

let objectB: ObjectB = { foo: { bar: '123', baz: '456' } };
let objectA: ObjectA = objectB; // Woohoo, no error
// @flow
type ObjectA = { +foo: { bar: string } };
type ObjectB = { foo: { bar: string, baz: string } };

let objectB: ObjectB = { foo: { bar: '123', baz: '456' } };
let objectA: ObjectA = objectB;

objectA.foo = {bar: 'oh-oh, deleted baz in objectB'}; //Error
// @flow
type ObjectA = { +foo: { +bar: { baz: string } } };
type ObjectB = { foo: { bar: { bax: string, baz: string } } };

let objectB: ObjectB = { foo: { bar: { bax: '123', baz: '456' } } };
let objectA: ObjectA = objectB; // Woohoo, no error
// @flow
type ObjectA = $ReadOnly<{ foo: { bar: string } }>;
type ObjectB = { foo: { bar: string, baz: string } };

let objectB: ObjectB = { foo: { bar: '123', baz: '456' } };
let objectA: ObjectA = objectB; // Woohoo, no error
// @flow
type ObjectA = { foo: { bar: string } };
type ObjectB = { foo: { bar: string, baz: string } };

let objectB: ObjectB = { foo: { bar: '123', baz: '456' } };
let objectA: $ReadOnly<ObjectA> = objectB; // Woohoo, no error
// @flow
type ObjectA = { foo: { bar: string } };
type ObjectB = { foo: { bar: string, baz: string } };

let objectB: ObjectB = { foo: { bar: '123', baz: '456' } };
let objectA: ObjectA = {...objectB} // Create a new object