代码之家  ›  专栏  ›  技术社区  ›  tru7

根据字段推断文本对象并集的类型

  •  0
  • tru7  · 技术社区  · 6 年前

    我在一个接口中有一些属性。将这些属性分为两个接口,然后声明两者的联合类型似乎是可行的。

    请看下面的简化情况,其中一个函数需要一个百分比或一个固定值。在每个接口中添加一个属性,声明它的一个类型(isPercent)并将该类型约束为特定值,允许函数的逻辑检测传递的参数类型,而typescript(令人惊讶的是)似乎也只能推断该类型。

    很难描述,但我希望代码能给你一个想法:

    interface IPcentFee { isPercent: true, percentFee: number }
    interface IFixedFee { isPercent: false, fixedFee: number }
    
    let parm = { isPercent: true, percentFee: 0.15 }
    
    function calculate(parm:IPcentFee | IFixedFee){
        let value = 100, discount
        if (parm.isPercent) 
            discount = value * parm.percentFee  // Here ts infers type of parm being IPecentFee
        else 
            discount = parm.fixedFee    // ts error: Property 'fixedFee' does not exist on type 'IPcentFee | IFixedFee'
        ....
    }
    

    TS似乎从条件中推断出IPcentfee类型 if (parm.isPercent) 但是为什么else子句不推断替代类型呢?

    样品经ts分析 版本2.9.1

    2 回复  |  直到 6 年前
        1
  •  3
  •   Daniel    6 年前

    确实很有趣。

    看看这个:

    interface IPcentFee { isPercent: true, percentFee: number }
    interface IFixedFee { isPercent: false, fixedFee: number }
    
    let parm = { isPercent: true, percentFee: 0.15 }
    
    function calculate(parm:IPcentFee | IFixedFee){
        let value = 100, discount
        if (parm.isPercent === true) // Comparing to literal `true`
            discount = value * parm.percentFee
        else 
            discount = parm.fixedFee // it works!
    }
    

    Playground

    只是改变一下 if (parm.isPercent) if (parm.isPercent === true) 是否按预期在每个分支中缩小了作业和类型。我不得不承认我不太清楚为什么另一种方法行不通。我想应该是 truthy / true 差异…但是,如前所示,您可以与文本值进行比较,这样就不需要手动断言。

    更新:

    事实上,它看起来是由于一个差异,但不是因为 诚实的 / 但是 falsy / false . 如果启用 strictNullChecks 标记你的代码只是工作。

    如果 严格检查 不是每种类型都启用 可空的 默认情况下,您仍然需要检查 isPercent null / undefined . 启用该标志使每种类型 非空的 默认情况下,实际上只有两种可能性(对于类型检查而言)

        2
  •  0
  •   prettyfly    6 年前

    带接口的联合类型在typescript中很有趣,通常需要有公共属性才能直接引用它们。所以你的界面可以是:

    interface IPcentFee { isPercent: true, fee: number }
    interface IFixedFee { isPercent: false, fee: number }
    

    以及访问:

    discount = value * parm.fee
    

    fee 可能很常见,因为你正在检查公共属性 isPercent .

    或者,您可以将else子句强制转换为以下语句,这样不会抛出错误。

    discount = (<IFixedFee>parm).fixedFee 
    

    Playground