Javascript 具有深子类型的流错误
根据flow的文档,这是可行的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
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