字符串转数字 String to Number
大约 3 分钟TC-Hard
字符串转数字 String to Number
题目
将字符串字面量类型转换为数字字面量类型,行为类似 Number.parseInt。
type Result = ToNumber<'123'> // 期望结果:123解答
type ToNumber<S extends string> =
S extends `${infer N extends number}` ? N : never只需一行。TypeScript 4.8 引入了模板字面量类型中的 infer ... extends 约束推断,使得这个问题几乎变得平凡。
工作原理
S extends `${infer N extends number}` ? N : never这告诉 TypeScript:"尝试将字符串 S 解析为一个包含 number 的模板。如果能解析,就将那个数字推断为 N。"
当 S = '123' 时,TypeScript 识别出 '123' 匹配模板 `${number}` 并推断 N = 123 作为数字字面量类型。
推导过程:
ToNumber<'123'>
→ '123' extends `${infer N extends number}` ? N : never
→ N = 123
→ 123 ✓
ToNumber<'0'>
→ N = 0 ✓
ToNumber<'abc'>
→ 'abc' 不匹配 `${number}`
→ never ✓深入分析
4.8 之前的解法
在 TypeScript 4.8 之前,infer ... extends 不存在。经典做法是用元组计数:
type ToNumber<S extends string, A extends any[] = []> =
`${A['length']}` extends S
? A['length']
: ToNumber<S, [...A, 1]>这个方案从 0 开始,通过不断增长元组 A 直到其长度(转为字符串后)匹配 S。能用但在 ~999 附近会触发递归限制。
旧方案工作过程:
ToNumber<'3'>
A = [] → '0' extends '3'?否
A = [1] → '1' extends '3'?否
A = [1,1] → '2' extends '3'?否
A = [1,1,1] → '3' extends '3'?是 → A['length'] = 3 ✓为什么 infer N extends number 能工作
TypeScript 4.8 新增了在条件类型中约束推断类型的能力。在模板字面量位置:
`${infer N extends number}`TypeScript 的模板字面量推断引擎会尝试将字符串解析为数字。如果成功,N 会被收窄为具体的数字字面量。支持的格式:
- 整数:
'42'→42 - 负数:
'-7'→-7 - 小数:
'3.14'→3.14 - 零:
'0'→0
无法解析的情况
ToNumber<''> // never(空字符串)
ToNumber<'abc'> // never(不是数字)
ToNumber<'12px'> // never(不像 parseInt,不支持部分解析)
ToNumber<' 42'> // never(前导空格)注意与 JavaScript 的 parseInt 不同,类型层面的版本要求整个字符串都是有效数字——不支持部分解析。
也适用于其他原始类型
同样的模式适用于布尔值和大整数:
type ToBool<S extends string> =
S extends `${infer B extends boolean}` ? B : never
type ToBI<S extends string> =
S extends `${infer N extends bigint}` ? N : never
type T1 = ToBool<'true'> // true
type T2 = ToBool<'false'> // false
type T3 = ToBI<'42'> // 42n负数和边界情况
type T1 = ToNumber<'-1'> // -1 ✓
type T2 = ToNumber<'0'> // 0 ✓
type T3 = ToNumber<'1e5'> // never(不支持科学计数法)
type T4 = ToNumber<'Infinity'> // never核心要点
infer N extends number在模板字面量中(TS 4.8+)是现代、简洁的类型层字符串转数字方式- 4.8 之前的元组计数方案仅适用于较小的非负整数,且有递归限制
- 带约束的模板字面量推断适用于
number、boolean、bigint和string - 与运行时
parseInt不同,类型层版本要求整个字符串都是有效数字
