深子类型的流错误

时间:2018-05-03 02:08:57

标签: javascript ecmascript-6 flowtype

根据流程的Subtypes of objects文档,这可行

// @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?

任何想法为什么?

2 个答案:

答案 0 :(得分:1)

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

将对象属性标记为协变

您尝试做的是将ObjectB投射到ObjectA。 Flow抱怨的原因是fooObjectA的类型默认为invariantfoo的{​​{1}}属性是ObjectB foo属性的子类型。要让Flow了解这一点,我们只需要将ObjectA属性标记为covariant

Try

foo

将该物业标记为"协变"基本上说你保证只阅读那个属性,你不会写信给它。请注意,如果删除了objectA的// @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 属性,它将从objectB中删除baz。通过将其标记为协变,如果您写入它,Flow将抛出错误:

Try

baz

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

Try

// @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

有关此类型的更多详细信息,请参阅depth subtyping上的Flow文档。

使用// @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具有一个完整的类型$ReadOnly<T>,可以将对象的所有属性标记为协变,因此您可能希望使用它:

Try

$ReadOnly<T>

或者您可以创建ObjectA的ReadOnly实例并单独保留ObjectA定义:

Try

// @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

创建新对象

或者,您可以使用跨页创建对象的新副本,并避免所有这些输入:

Try

// @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

答案 1 :(得分:0)

据我所知,一种可能的方法是展开对象。没有这个流程就无法读取属性。

SELECT * FROM `def_questions` where `question` LIKE '%What is your Name%'