如何在 NaN 和 Infinity 上使用条件类型

Posted

技术标签:

【中文标题】如何在 NaN 和 Infinity 上使用条件类型【英文标题】:How to use conditional types on NaN and Infinity 【发布时间】:2021-12-08 18:08:51 【问题描述】:

我正在 TypeScript 中创建一个函数,它本质上扩展了 typeof 关键字的功能,包括在已知类型时显示适当的 IntelliSense(通过条件类型)。我的所有其他自定义类型都可以正常工作,因此它们仅在已知的 1 返回类型中显示 IntelliSense,但我不确定如何使其专门针对 NaN 和 Infinity 值工作。我相信这是因为这些被忽略为“数字”文字类型。 (下面的工作示例)

public static async type(value: number): Promise<'number' | 'nan' | 'infinity'> // would rather this only show just 1 type
public static async type(value: []): Promise<'array'>
public static async type(value: Promise<any>): Promise<'promise'>
// and several more...
public static async type(value: any): Promise<T_detectType> 
   // do stuff

我的问题:是否可以基于 NaN 和/或 Infinity 创建条件类型? (下面的非工作示例)

public static async type(value: NaN): Promise<'nan'>
public static async type(value: Number.POSITIVE_INFINITY | Number.NEGATIVE_INFINITY): Promise<'infinity'>

我可以根据需要提供更多详细信息,但我不确定您可能需要什么,并且我正在努力使这个问题保持简洁。

【问题讨论】:

TypeScript 没有对应于 NaNInfinity-Infinity 的数字文字类型。在microsoft/TypeScript#15135 中提出建议并拒绝;它偶尔会作为建议提出,但从未实施过。所以没有支持你正在尝试做的事情 另见github.com/microsoft/TypeScript/issues/36964 @jcalz 谢谢!您可以将此添加为答案吗?我想留出一些额外的时间来看看是否有人能想出一个可行的替代方案。但是,我会假设您是完全正确的,如果没有人提供可行的替代方案,我会在明天将其标记为正确答案。 @NicholasSummers 没有人会提供可行的替代方案 【参考方案1】:

无论好坏,TypeScript 没有 literal types 代表 NaNInfinity-Infinity。可用于NaNInfinity-Infinity 的最窄类型仅为number。因此,例如,虽然使用数字文字初始化的 const 通常具有文字类型:

const x = 1.234;
// const x: 1.234

NaNInfinity 不会发生同样的情况:

const y = NaN;
// const y: number
const z = -Infinity;
// const z: number

我想不出比放弃更糟糕的解决方法。你可以想象提供一些simulated nominal type

type NaN = number &  NaN: true ;
type Infinity = number &  Infinity: true ;
type NegInfinity = number &  NegInfinity: true ;

但是你需要使用type assertions 来使用它们:

const w = NaN as NaN;
const v = Infinity as Infinity;
const u = -Infinity as NegInfinity;

如果你的目标是写 Blah.type(NaN) 并让 Promise&lt;'nan'&gt; 出现,你只能通过写 Blah.type(NaN as NaN) 来实现这个目标,这很愚蠢,尤其是因为没有什么能阻止某人写 Blah.type(123 as NaN)

在 TypeScript 中,NaNInfinity-Infinity 只是 number 类型,仅此而已。


至于改变这个:

microsoft/TypeScript#15135 拒绝了功能请求,要求提供此类支持。从阅读该问题(以及ms/TS#15356 的链接设计讨论)来看,似乎没有人能够阐明一个足够重要的用例来支持它。支持 NaN 作为文字可能会很烦人,因为例如,NaN === NaNfalse

就个人而言,我倾向于同意我们关心NaN 类型,因为它们是falsy,并且跟踪虚假性是值得的。但是在实现数字文字类型的拉取请求中,实现者的comment 说虚假并不重要,他想不出任何有意义的“场景,您可以将NaNInfinity 用作单例用于重载的类型、判别值或文字值。”

microsoft/TypeScript#32277 存在一个未解决的问题,要求提供 Infinity-Infinity 文字类型,而不是 NaN;它目前被标记为“等待更多反馈”,这意味着他们希望看到 cmets 在考虑实施之前描述令人信服的用例。

microsoft/TypeScript#36964 存在一个问题,该问题表明缺乏对类似 NaN 的类型的考虑会导致不正确的窄化... 一个虚假的 number 被假定为 0 而实际上应该是 @ 987654365@ 是正确的。它也被标记为等待反馈,请求者似乎在说它应该是number,因为typeof NaNnumber(而不是说应该有一个NaN 类型)。但它是相关的。

几乎可以想象,足够多的人可以将 cmets 添加到这两个未解决的问题中,说明应该如何添加文字 NaNInfinity-Infinity 类型,并详细说明足够有说服力最终导致此问题的用例即将发生。但这很可能不会发生。在我看来,typeof 辅助函数的更强类型不太可能被视为特别引人注目。因此,尽管去那里给他们一个 ? 并描述您正在尝试做的事情可能不会有任何伤害,但我不会指望它会产生任何影响。

目前,我认为您可能应该放弃尝试将NaNInfinity-Infinitynumber 区分开来,不幸的是。

Playground link to code

【讨论】:

以上是关于如何在 NaN 和 Infinity 上使用条件类型的主要内容,如果未能解决你的问题,请参考以下文章

你如何让 VB6 用 +infinity、-infinity 和 NaN 初始化双精度数?

如何解决某些图像上的颤振“Infinity or NaN toInt”

java中Infinity(无限)和NaN

浮点数或双精度数的 NaN 和 Infinity 如何存储在内存中?

如何在我的 numpy 数组中找到 NaN/infinity/对于 dtype('float64') 来说太大的值?

使用 Infinity 和 NaN 禁用异常