Menu

TypeScript 字符串转数字(以及数字转字符串)

在 TypeScript 中用 Number()、parseInt()、parseFloat() 或一元 + 把字符串转换为数字,看看它们各自如何处理 "42px"、"" 和 "1e3" 这样的输入,如何安全地检查 NaN,以及如何把数字转回字符串。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

在 TypeScript 中把字符串转换为数字,就调用 Number(text)。结果的类型是 number,当文本不是有效数字时,值为 NaN。如果文本末尾带有其他字符,比如 "42px",就用 parseInt(text, 10) 或 parseFloat(text)。

这四种转换返回的类型都是 number。TypeScript 并不知道文本是否有效;无效的字符串得到的仍然是 number,只是值为 NaN。

为什么必须转换

表单字段、URL 参数、环境变量和文件内容拿到时都是字符串。TypeScript 不允许你把字符串用在需要数字的地方:

index.ts(3,23): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.

对字符串使用 -、* 和 / 做算术运算会报错。+ 是允许的,但它会拼接字符串,所以 "3" + 10 得到的是字符串 "310",这就是为什么必须先转换:Number(quantity) * 10。

类型断言也帮不上忙。quantity as number 会被拒绝(TS2352),而用 as unknown as number 强行断言只是让编译器闭嘴:运行时这个值仍然是字符串。

Number、parseInt、parseFloat 与一元加号对比

这四种方法在干净的输入上结果一致,其他情况下各不相同。下表是它们在 Node 上的实际输出:

输入Number(s)+sparseInt(s, 10)parseFloat(s)
"42"42424242
"3.99"3.993.9933.99
"42px"NaNNaN4242
""00NaNNaN
" 3 "3333
"1e3"1000100011000
"0x1F"313100
"1,000"NaNNaN11
"12_000"NaNNaN1212
"abc"NaNNaNNaNNaN

表格背后的规则:

  • Number 和一元 + 完全相同。它们会先去掉首尾空白再转换整个字符串,能识别 1e3 和 0x 十六进制,只要有剩余字符就返回 NaN。空字符串或只含空白的字符串会变成 0。
  • parseInt 和 parseFloat 从开头读起,遇到第一个用不了的字符就停下,所以 "42px" 和 "1,000" 会得到部分数字。空字符串得到 NaN。
  • parseInt 会丢掉小数部分,也不认识指数:"1e3" 读到 e 就停了。
  • 数字分隔符(12_000)在源代码中有效,在字符串中无效。

验证输入时,Number 是更严格的选择。parseInt 和 parseFloat 适合确实带有单位或后缀的文本,比如 CSS 尺寸。

处理无效输入:NaN

NaN 的类型是 number,所以编译器从不会对它发出警告。你需要自己用 Number.isNaN 或 Number.isFinite 检查结果:

返回 number | undefined 让失败成为类型的一部分,每个调用方都必须先处理它,才能做算术运算。Number.isFinite 还会拒绝 Infinity,而 Number("Infinity") 会照样返回它。

避免使用全局的 isNaN(x):它会先转换参数,所以在 JavaScript 中 isNaN("abc") 是 true。TypeScript 的声明只接受 number,传入字符串会报错 TS2345,这正是在提示你:对已经转换好的值使用 Number.isNaN。

字符串转整数

调用 parseInt 时一定要传第二个参数,也就是基数:十进制文本传 10。它是可选的,但能写明意图,对其他进制也很重要。要从带小数的字符串得到整数,先转换,再显式取整。

parseInt 期望的参数是字符串:parseInt(12.7) 会报编译错误(TS2345),这一点很有用,因为在 JavaScript 中对数字调用 parseInt 会先把它转成文本,对 0.0000005 这样的值会给出错误的答案(返回 5)。数字请用 Math.trunc。对于超过 Number.MAX_SAFE_INTEGER 的整数,BigInt(text) 能解析出完整的值(遇到无效文本时会抛出 SyntaxError,而不是返回 NaN)。

数字转字符串

String(n)、n.toString() 和 `${n}` 都能把数字转换为最短的字符串形式。格式化方法能提供更多控制:

toFixed 对二进制值取整,而不是对你写下的十进制数,所以 (1.005).toFixed(2) 是 "1.00":1.005 实际存储的值略小于 1.005。处理金额时,用整数“分”来保存,或者用 Intl.NumberFormat 来格式化。

String(n) 对 null 和 undefined 也有效(分别得到 "null" 和 "undefined"),而在 strict 下 n.toString() 会报编译错误,因为这个值可能不存在。

速查表

任务代码结果类型
字符串转数字(严格)Number(s) 或 +snumber(可能是 NaN)
从文本开头取整数parseInt(s, 10)number(可能是 NaN)
从文本开头取小数parseFloat(s)number(可能是 NaN)
检查结果Number.isFinite(n)、Number.isNaN(n)boolean
大整数BigInt(s)bigint
数字转字符串String(n)、n.toString()、`${n}`string
固定小数位n.toFixed(2)string
其他进制n.toString(16)string
千位分隔符n.toLocaleString("en-US")string

常见问题

TypeScript 中如何把字符串转换为数字?

用 Number(text)。它返回一个 number:有效的数字文本得到对应的值,其他情况得到 NaN,空字符串或只含空白的字符串得到 0。当文本末尾可能带有其他字符(比如 "42px")时,用 parseInt(text, 10) 或 parseFloat(text)。

能用 as number 把字符串转成数字吗?

不能。"42" as number 会报编译错误(TS2352),即使通过 unknown 强行断言,断言也只改变编译器看到的类型:运行时这个值仍然是字符串 "42"。要用 Number()、parseInt() 或 parseFloat() 真正转换值。

TypeScript 中 Number() 和 parseInt() 有什么区别?

Number 转换整个字符串,只要有一部分不是数字就返回 NaN,所以 Number("42px") 是 NaN。parseInt 从开头读取数字,遇到第一个非数字字符就停止,所以 parseInt("42px", 10) 是 42,而且会丢掉小数部分。Number("") 是 0,而 parseInt("") 是 NaN。

如何检查一个字符串是不是有效的数字?

先转换,再检查结果:const n = Number(text); if (text.trim() !== "" && Number.isFinite(n)) { ... }。空字符串检查很重要,因为 Number("") 是 0。用 Number.isNaN,不要用全局的 isNaN,而且 TypeScript 本来也只接受给后者传 number 参数。

TypeScript 中如何把数字转换为字符串?

String(n)、n.toString() 或模板字符串 `${n}` 得到的结果都一样。需要固定小数位时用 n.toFixed(2),需要其他进制时用 n.toString(16),需要千位分隔符时用 n.toLocaleString("en-US")。

Coddy 编程语言插图

和 Coddy 一起学编程

开始