通过字段推断文字对象联合的类型
Infer type of literal objects union by a field
我在界面中有一些非此即彼的属性。将这些属性分成两个接口,然后声明两者的联合类型似乎是可行的方法。
请查看以下简化情况,其中函数需要百分比或固定值。向每个接口添加一个 prop,声明它是否是一种类型(isPercent)并将类型限制为特定值,允许函数的逻辑检测传递的参数类型,并且打字稿 - 令人惊讶地 - 似乎也可以推断类型但仅.
很难描述,但我希望代码能给你思路:
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 似乎从条件 if (parm.isPercent)
推断出 IPcentFee 类型,但为什么 else 子句不推断替代类型?
样本由ts version 2.9.1
分析
带接口的联合类型在 Typescript 中很有趣,通常需要有共同的属性才能直接引用它们。所以你的界面可能是:
interface IPcentFee { isPercent: true, fee: number }
interface IFixedFee { isPercent: false, fee: number }
并通过以下方式访问:
discount = value * parm.fee
fee
可以是常见的,因为您正在检查常见的 属性 isPercent
.
或者,您可以将 else 子句强制转换为以下内容,这样不会引发任何错误。
discount = (<IFixedFee>parm).fixedFee
确实很有趣。
看看这个:
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!
}
只需将 if (parm.isPercent)
更改为 if (parm.isPercent === true)
即可完成工作,并且每个分支中的类型都会按预期缩小。我不得不承认我不完全确定为什么另一种方法行不通。我想这是由于 truthy
/true
差异造成的...但是,正如所示,您可以与字面值进行比较,因此您不需要手动断言。
更新:
事实上,它看起来是由于差异,但不是 truthy
/true
,而是 falsy
/false
。如果您启用 strictNullChecks
标志,您的代码就可以正常工作。
如果 strictNullChecks
未启用,默认情况下每个类型都是 nullable,因此您仍然需要检查 isPercent
到 null
/ undefined
。启用该标志使每个类型默认为 不可空 所以实际上只有两种可能性(对于类型检查)是 true
或 false
.
我在界面中有一些非此即彼的属性。将这些属性分成两个接口,然后声明两者的联合类型似乎是可行的方法。
请查看以下简化情况,其中函数需要百分比或固定值。向每个接口添加一个 prop,声明它是否是一种类型(isPercent)并将类型限制为特定值,允许函数的逻辑检测传递的参数类型,并且打字稿 - 令人惊讶地 - 似乎也可以推断类型但仅.
很难描述,但我希望代码能给你思路:
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 似乎从条件 if (parm.isPercent)
推断出 IPcentFee 类型,但为什么 else 子句不推断替代类型?
样本由ts version 2.9.1
分析带接口的联合类型在 Typescript 中很有趣,通常需要有共同的属性才能直接引用它们。所以你的界面可能是:
interface IPcentFee { isPercent: true, fee: number }
interface IFixedFee { isPercent: false, fee: number }
并通过以下方式访问:
discount = value * parm.fee
fee
可以是常见的,因为您正在检查常见的 属性 isPercent
.
或者,您可以将 else 子句强制转换为以下内容,这样不会引发任何错误。
discount = (<IFixedFee>parm).fixedFee
确实很有趣。
看看这个:
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!
}
只需将 if (parm.isPercent)
更改为 if (parm.isPercent === true)
即可完成工作,并且每个分支中的类型都会按预期缩小。我不得不承认我不完全确定为什么另一种方法行不通。我想这是由于 truthy
/true
差异造成的...但是,正如所示,您可以与字面值进行比较,因此您不需要手动断言。
更新:
事实上,它看起来是由于差异,但不是 truthy
/true
,而是 falsy
/false
。如果您启用 strictNullChecks
标志,您的代码就可以正常工作。
如果 strictNullChecks
未启用,默认情况下每个类型都是 nullable,因此您仍然需要检查 isPercent
到 null
/ undefined
。启用该标志使每个类型默认为 不可空 所以实际上只有两种可能性(对于类型检查)是 true
或 false
.