如何使用Flow定义具有可选属性的对象的并集?

时间:2017-06-17 16:44:20

标签: javascript types flowtype

我有一个处理两种类型参数的函数:string和object。预期有3种不同的对象结构。这最多包含4种可能的类型:

type URL = string;
type Item = {| href: string |};
type ItemList = {| results: Item[] |};
type Params = {| offset?: number, limit?: number |};

所以函数的选项类型是:

type Options = URL | Item | ItemList | Params;

以下是实际功能:

// No properties of "Params" are required
// so if they're all omitted, Params === {}
function request(opts: Options = {}) {
  if (typeof opts === 'string') {
    return 'opts is an URL';
  }

  if (typeof opts.href === 'string') {
    return 'opts is an item';
  }

  if (Array.isArray(opts.results)) {
    return 'opts is a list of items';
  }

  // Three of the four types are caught
  // we're left with "Params" which may or may not
  // have a "offset" and "limit" property.
  // Destructuring to undefined values is fine here.
  // Still, flow complains about the type not being met.
  const { offset, limit } = opts;
  return 'opts are parameters';
}

Flow抱怨一些事情:

  1. opts = {}会引发不兼容错误。由于不需要Params的属性,不应该将空对象匹配吗?请注意,opts = { offset: undefined }会清除错误。
  2. 属性"偏移"和"限制"声明未找到。由于它们都不是必需的,因此undefined不应该是有效值吗?从而解构好吗?
  3. 总结我的问题:

    如何定义接受不同类型对象的类型,其中一个没有必需的属性?

    修改:run the flow code in your browser

1 个答案:

答案 0 :(得分:1)

查看Flowtype - making a sealed empty object以获取第一个问题的答案。

对于你的第二个,答案基本上是Flow不完全支持这种类型的改进。 Disjoint unions是为此用例设计的,但您必须为所有对象添加一个discriminator属性。显然,这将需要对您的代码进行一些重大更改。由你来决定这是否可行。

如果不可行,最好的办法可能只是在此函数中强制转换any,并确保为返回值提供类型注释。看起来它足够小,人类很容易理解,所以这里的类型检查的好处可能不值得努力。当然这是一个最好留给你的判断电话。