如何在TypeScript中为NaN、Infinity使用条件类型?
核心原因
TypeScript 截至 5.x 版本未将NaN、Infinity、-Infinity设为独立的字面量类型,上述值的静态类型会被统一推断为number,因此直接声明value: NaN的重载无法触发匹配,同时你当前的重载顺序也存在问题:TS 重载是从上到下优先匹配最先符合的规则,你把范围更大的number重载放在了细分重载前面,就算存在对应的细分类型也不会被命中。
可行实现方案
1. 烙印类型+重载顺序调整
首先定义专属烙印类型实现类型层面的区分:
type NaN = number & { __brand: 'nan' } type Infinity = number & { __brand: 'infinity' }
调整重载顺序,将细分规则放在最前面:
// 细分规则优先 public static async type(value: NaN): Promise<'nan'> public static async type(value: Infinity): Promise<'infinity'> public static async type(value: number): Promise<'number' | 'nan' | 'infinity'> public static async type(value: []): Promise<'array'> public static async type(value: Promise<any>): Promise<'promise'> // 其余重载省略 public static async type(value: any): Promise<T_detectType> { // 运行时逻辑不变,用原生方法判断即可 if (typeof value === 'number') { if (Number.isNaN(value)) return 'nan' as T_detectType if (!Number.isFinite(value)) return 'infinity' as T_detectType return 'number' as T_detectType } // 其余类型判断逻辑 }
在明确入参为NaN/Infinity的场景下,添加对应类型断言即可触发精准类型提示:
const nanRes = await Utils.type(NaN as NaN) // 类型为 Promise<'nan'> const infRes = await Utils.type(Infinity as Infinity) // 类型为 Promise<'infinity'>
2. 类型守卫自动收窄
如果需要在运行时判断后自动触发类型匹配,可以配套编写类型守卫函数:
function isNaN(val: number): val is NaN { return Number.isNaN(val) } function isInfinity(val: number): val is Infinity { return !Number.isFinite(val) && !Number.isNaN(val) } const input = Math.sqrt(-1) if (isNaN(input)) { const res = await Utils.type(input) // 自动收窄为 Promise<'nan'> }
内容的提问来源于stack exchange,提问作者Nicholas Summers
相关产品推荐
相关产品推荐

