【问题标题】:Disjoint unions without tags没有标签的不相交联合
【发布时间】:2017-02-18 16:44:34
【问题描述】:

我有这种情况,没有办法有意义地改变数据结构。所以我不能添加标签。 有没有办法区分没有标签的类型?我尝试了鸭式打字,但它不起作用。见我的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

【问题讨论】:

    标签: javascript flowtype


    【解决方案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。显然,使用精确类型的缺点是您的对象不能包含无关字段。但是,如果您绝对不能添加鉴别器字段以使用不相交的联合,我认为这是最好的选择。

    【讨论】:

      【解决方案2】:

      这确实有道理,因为您的输入没有说 Done 不能有 count 属性。

      使用精确的对象类型似乎部分有效,从某种意义上说,它确实可以正确优化,正如您在 example 中看到的那样。遗憾的是,您还必须在 else 中进行显式检查。

      By AugustinLF

      【讨论】:

      • 如果count0message'',此方法将失败。我猜我的回答被否决了,因为乍一看,我的类型看起来像是改变了你的数据结构,而你说你不能这样做。但是,添加可选字段仍然与您描述的数据兼容,并且此表单允许您检查!== undefined,它将处理虚假情况。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-31
      • 2018-01-05
      • 1970-01-01
      • 1970-01-01
      • 2010-09-11
      • 1970-01-01
      相关资源
      最近更新 更多