没有标签的脱节联盟

时间:2017-02-15 10:48:50

标签: javascript flowtype

我有这种情况,没有办法有意义地改变数据结构。所以我无法添加标签。 有没有办法区分没有标签的类型?我试过鸭子,但它不起作用。查看我的example

type Result = Done | Error; // a disjoint union type with two cases
type Done = { count: number }
type Error = { message: string }

const doSomethingWithDone = (obj: Done) => {/*...*/}
const doSomethingWithError = (obj: Error) => {/*...*/}

const f = (result: Result) => {
  if (result.count) {
    doSomethingWithDone(result)
  } else {
    doSomethingWithError(result)
  }
}

错误是:

 5: const doSomethingWithDone = (obj: Done) => {/*...*/}
                                      ^ property `count`. Property not found in
 10:     doSomethingWithDone(result)
                             ^ object type 
 6: const doSomethingWithError = (obj: Error) => {/*...*/}
                                       ^ property `message`. Property not found in
 12:     doSomethingWithError(result)
                              ^ object type

2 个答案:

答案 0 :(得分:1)

Flow不支持这种优雅的东西,因为它不相交联盟。但是,确切类型可以提供帮助。你的例子中的问题是我能做到

const x: Error = {message: 'foo', count: 'bar'};
f(x);

赋值有效,因为我的对象文字满足x接口。所以,虽然你知道如果某个东西是Error,它有一个message属性,你不知道它有什么其他属性。因此,检查count属性是否存在并不能证明您拥有Done类型的有效对象。

确切类型可以在这里提供帮助:

type Result = Done | Error; // a disjoint union type with two cases
type Done = {| count: number |}
type Error = {| message: string |}

const doSomethingWithDone = (obj: Done) => {/*...*/}
const doSomethingWithError = (obj: Error) => {/*...*/}

const f = (result: Result) => {
  if (result.count) {
    doSomethingWithDone(result)
  } else if (result.message) {
    doSomethingWithError(result)
  }
}

// Expected error. Since Error is an exact type, the count property is not allowed
const x: Error = {message: 'foo', count: 'bar'};
f(x);

tryflow link

请注意,除了使类型完全正确外,我还必须将else更改为else if。显然,使用精确类型的缺点是你的对象不能有无关的字段。但是,如果你绝对不能添加一个鉴别器字段来使用不相交的联合,我认为这是最好的选择。

答案 1 :(得分:0)

  

这是有道理的,因为你的打字并没有说Done不能有计数属性。

     

正如您在example中所看到的那样,使用精确对象类型似乎在某种程度上可以正常工作。可悲的是,你还必须在别的地方做一个明确的检查。

By AugustinLF