在下面的代码中,我不理解为什么Flow会拒绝我的kv
元组。
// @flow
type String = {
type: "string",
value: string
};
type Number = {
type: "number",
value: number
};
type Value = Number | String;
type Foo = { foo: "bar" } & Value;
let obj: Foo = {
foo: "bar",
type: "number",
value: 42
};
let kv: [string, Foo] = ["obj", obj];
Flow似乎成功检查obj
为Foo
,但不希望我在[string, Foo]
元组中使用它。
确实我收到以下错误:
23: let kv: [string, Foo] = ["obj", obj];
^ intersection type. This type is incompatible with
15: type Foo = { foo: "bar" } & Value;
^ union: Number | String
发生了什么事?
答案 0 :(得分:1)
很遗憾"尝试流程"并没有为您提供完整的类型错误跟踪。如果你去here并点击" json"你可以深入了解并了解更多关于发生了什么的事情。
想到这一点的方法是继承问题。 Flow试图确定Foo是什么类型。因为在Foo的声明中没有任何内容可以表明它是{foo}&数字或{foo}& String,Flow似乎天真地试图同时应用它们。
所以在第23行,流程说,"类型不是Foo因为我希望属性"类型"成为"字符串"和"价值"输入" number"。但如果你换了它,Flow仍然会出错。
这是我想到这个问题的另一种方式:
class String
class Number
class Value extends String || Number // <= unable to determine what Foo is extending
type Foo = { stuff } & Value // <== ...locked-in non-deterministic
在这种情况下,Flow无法确定&#34; Foo&#34;正在扩展,但如果某个变量被赋值为Value类型,则有一些逻辑来解析该类型。但...
当创建Foo别名时,Value仍然是非确定性的,它就像Flow试图锁定Foo一样。一旦访问属性,Flow就会抛出错误。
幸运的是,有两种简单的方法可以解决这个问题。
第一个涉及一个名为disjoint unions的功能。 Here's a working example
type Foo = { foo: "bar" }
type String = Foo & {
type: "string",
value: string
};
type Number = Foo & {
type: "number",
value: number
};
type Value = Number | String;
let obj: Foo = {
foo: "bar",
type: "number",
value: 42
};
let kv: [string, Foo] = ["obj", obj]; // no errors!
为什么这样做?再次,假设您使用继承模式编写了这个:
class Foo;
class String extends Foo; // <== deterministic
class Number extends Foo; // <== deterministic
var Value = String | Number // <== enum of certain classes, so still deterministic
如果您获取Flow的最新主分支,那么还有一个很酷的功能,对象类型的传播。 Here's an example:
// @flow (master branch)
type String = {
type: "string",
value: string
};
type Number = {
type: "number",
value: number
};
type Value = Number | String;
type Foo = { foo: "bar", ...Value }
let obj: Foo = {
foo: "bar",
type: "number",
value: 42
}; // no error!
let otherObj: Foo = {
foo: "bar",
type: 'string',
value: 'I am a string',
}; // no error!