代码之家  ›  专栏  ›  技术社区  ›  rony l

类型缩小对(几乎)受歧视的工会不起作用

  •  1
  • rony l  · 技术社区  · 2 周前

    给定以下类型定义:

    type A = { a: string } | { a?: undefined; b: string }
    

    这基本上意味着,如果你提供 a ,这就是您应该提供的全部内容。如果您不提供 ,或者您提供 但它是 undefined ,您还必须提供 b

    我希望能够访问 b 如果 根据以下代码未定义:

    let t = true
    // The purpose in this line of code is to confuse the compiler such that it won't narrow the definition right in this line of code.
    const z: A = t ? { a: 'a' } : { b: 'b' }
    
    if (z.a) {
      console.log(z.a)
    } else {
      console.log(z.b)
    }
    

    我得到的是以下错误消息:

    Property 'b' does not exist on type 'A'.
      Property 'b' does not exist on type '{ a: string; }'
    

    这里有 link 带相关代码前往ts游乐场。

    我期待着一个类型安全的解决方案。即,不使用不安全的字符串来测试属性的存在,例如 hasOwnProperty('b') 并且没有类型断言。

    这可能吗?

    2 回复  |  直到 2 周前
        1
  •  2
  •   Nicholas Tower    2 周前

    我得到的是以下错误消息:

    Property 'b' does not exist on type 'A'.
      Property 'b' does not exist on type '{ a: string; }'
    

    您收到该错误消息的原因是,有可能进入else块,但上仍然有一个字符串 z.a 所有物如果 z.a 是一个空字符串 "" 。所以事实上,在其他情况下,类型根本没有缩小。

    如果你把它切换到这个位置,它就会工作:

    if (typeof z.a === 'string') {
      console.log(z.a)
    } else {
      console.log(z.b)
    }
    

    Playground link

        2
  •  1
  •   meriton    2 周前

    您的检查应该更明确:

    if (z.a !== undefined) {
      console.log(z.a)
    } else {
      console.log(z.b)   // compiles
    }
    

    你的代码不起作用的原因是 z.a 可以是 '' ,这是一个字符串,但是falsy,这将导致其他分支被用于没有的东西 z.b ...