javascript - 为什么 Flow 拒绝由并集的交集组成的元组?

标签 javascript flowtype

在下面的代码中,我不明白为什么 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

这是怎么回事?

最佳答案

不幸的是,“Try Flow”没有为您提供完整的类型错误跟踪。如果你去here然后单击“json”,您可以深入了解并了解有关正在发生的事情的更多信息。

问题:非确定性

可以将其视为继承问题。 Flow 试图确定 Foo 是什么类型。因为在 Foo 的声明中没有指明它是 { foo } & Number 还是 { foo } & String,所以 Flow 似乎天真地尝试同时应用这两者。

所以在第 23 行,流程说,“类型不是 Foo,因为我希望属性“类型”是“字符串”,“值”是类型“数字”。但是如果你切换它, 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 无法确定“Foo”扩展的是什么,但如果某个变量被分配了 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!

关于javascript - 为什么 Flow 拒绝由并集的交集组成的元组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42039969/

相关文章:

javascript - Typescript 动态属性输入

javascript - JS - 使用 window.print() 打印字符串

javascript - Sprite 向某一特定点移动的方式

Javascript:什么时候应该使用 function_name.apply ?

javascript - 如何根据参数字符串定义返回类型?流式javascript

javascript - 对定义的属性使用 Object.defineProperty

jshint - 我如何继续使用 jshint 与 facebook flow?

json - 如何获得 Flow 类型检查器覆盖的 JSON.parse 结果?

flowtype - 如何使用流接口(interface)而不提示 "interface"是严格模式下的 future 保留字?

reactjs - 流量: How do I type-annotate a local/global variable?