🔎 搜索词
泛型,缩小,空字符串,false,假值
🕗 版本与回归信息
这是我尝试的每个版本的行为,但似乎在TS v4.2.3及更早版本中表现得稍微差一些。
⏯ Playground链接
https://www.typescriptlang.org/play?ts=5.5.0-dev.20240417#code/GYVwdgxgLglg9mABKSBGAPAFUQUwB5Q5gAmAzomCALYBGOATogD4UgA2bzi4xOwMYHMS7AAhm1I4uAcmkA+ABR4AXK1oMumAJSIA3gCgAkPRxQQ9JHmYsefAUIDc+gL76U0eEncAmLLgJEZGp0jCyUHFy2-ILCLGISUiyyiirBGizaekYmZhaIVgD8+YhyiAAMiEVWqgC01flOru6wCMjgEADMfviEJOSU6qGsETYkdjEi4pIy8kqqAyGaOgbGpuaWlYgAsqJQABYAdKI0pEo6qniN+voQCKRQ+fPUi6O80UKIALxtaAqyWk5bmB7ogAJ5fH4QbwKGodAE3O4PABeEPcHRhcIcQA
💻 代码
function func1<T extends number | null | undefined | false | ''>(x: number | T) {
return x || undefined;
}
function func2<T extends number | null | undefined | false | ''>(x: number | T) {
return x ? x > 0 ? x : -x : x;
}
function func3<T extends number | null | undefined | false | ''>(x: number | T) {
return x ? Math.abs(x) : x;
}
const x: number | undefined = func1('');
const y = func2(-3);
const z = func3(-3);
🙁 实际行为
func1
的推断返回类型可以包含false
或''
,取决于T
。这是错误的,因为x || undefined
永远不会导致false
或''
,因此不应出现在结果类型中。func2
无法通过类型检查:Operator '>' cannot be applied to types 'number | NonNullable<T>' and 'number'.
。这是错误的,因为真值检查应该将x
缩小到number
。(请注意,func3
之所以能够通过类型检查,是因为Math.abs
的签名似乎提供了补充信息,可以将x
缩小到number
。)
🙂 预期行为
func1
的推断返回类型应该是number | undefined
,无论T
如何。func2
应该能够通过类型检查,已经将number
缩小为x1m20n20,真值检查将其缩小为x1m20n20。
关于问题的附加信息
如果不使用泛型定义函数,所有函数都“正确”地工作,但这还不够,因为无论如何参数类型,func2
和func3
的返回类型始终是number | null | undefined | false | ''
。
我实际的使用场景是创建将数字输入转换并传播假值的函数。我已经在使用需要缩小的地方使用类型Assert来解决这个问题。
2条答案
按热度按时间bttbmeg01#
TS没有"
T
的真值"或"所有真值"的类型级表示,因此在任何需要写下类型的点上,最佳选择是NonNullable<T>
,它是一个声音但不完整的超集(当它不应该包括''
时)。avkwfej42#
但是,从联合类型中提取或排除假值类型似乎并不那么麻烦,就像NonNullable排除null和undefined并在这种情况下使用它们一样。如果T包括number,那么两个分支都必须包括number,因为没有NaN类型,但我认为你可以用Extract和Exclude完成这部分工作。
当然,我不知道这个改变涉及到的所有内容,所以这可能是一个困难的要求。