TypeScript 中的 number、bigint 与 string
摘要
number、bigint 和 string 都是 TypeScript 的原始类型。本篇重点整理它们的声明、推断、字面量类型、运算规则及常见误区。
背景
TypeScript 在 JavaScript 原始值的基础上增加了静态类型检查。理解这三个类型时,需要同时区分:
- 基础类型 :表示一类值,如
number、bigint、string。 - 字面量类型 :只表示一个确定的值,如
100、100n、'success'。 - 运行时值:类型检查最终仍遵循 JavaScript 的数值、字符串和运算规则。
类型对比
| 类型 | 可表示的值 | 字面量示例 | typeof 结果 |
|---|---|---|---|
number |
整数、浮点数、NaN、Infinity 等 |
100、3.14 |
'number' |
bigint |
任意精度的整数 | 100n |
'bigint' |
string |
文本字符串 | 'hello'、"hello"、hello |
'string' |
注意事项 :类型标注应使用小写的
number、bigint、string,不要使用包装对象类型Number、BigInt、String。
number
核心概念
- 定义 :
number表示 JavaScript 中的普通数值,不单独区分整数和浮点数。 - 存储方式:普通数值采用 IEEE 754 双精度浮点数表示。
- 安全整数范围 :能够被精确表示的整数范围是
-(2^53 - 1)到2^53 - 1,边界可通过Number.MIN_SAFE_INTEGER和Number.MAX_SAFE_INTEGER获取。 - 特殊值 :
NaN、Infinity和-Infinity也属于number。 - 官方文档 :The primitives: string, number, and boolean
声明与类型推断
ts
let count = 100;
let price: number = 19.9;
const statusCode = 200;
let fixedCode: 200 = 200;
console.log(typeof count); // 输出: number
count使用let声明,通常会拓宽为number。price显式标注为number,可以接收不同的普通数值。statusCode使用const声明,类型会被推断为字面量类型200。fixedCode被显式限制为字面量类型200,不能赋值为其他数字。
不同进制的数字字面量
ts
const decimal = 20;
const binary = 0b10100;
const octal = 0o24;
const hexadecimal = 0x14;
console.log(decimal === binary && binary === octal && octal === hexadecimal); // 输出: true
这些写法只影响代码中的表示形式,运行时得到的值都属于 number。
精度问题
ts
const unsafeInteger = Number.MAX_SAFE_INTEGER + 1;
console.log(unsafeInteger === Number.MAX_SAFE_INTEGER + 2); // 输出: true
console.log(0.1 + 0.2 === 0.3); // 输出: false
- 超出安全整数范围后,相邻整数可能无法准确区分。
- 浮点数采用二进制表示,某些十进制小数无法被精确存储。
- 金额计算不能直接假定浮点运算绝对精确,常见做法是转换为最小货币单位后使用整数计算。
注意事项
- 判断一个值是否为
NaN时,优先使用Number.isNaN(),因为NaN !== NaN。 - 需要判断整数是否仍在安全范围内时,可以使用
Number.isSafeInteger()。 - 如果需要处理超过安全整数范围的整数,应考虑使用
bigint,而不是继续使用number。
bigint
核心概念
- 定义 :
bigint是 ES2020 提供的任意精度整数类型,适合表示超出number安全整数范围的整数。 - 限制:只能表示整数,不能表示小数。
- 类型关系 :
bigint与number是两个独立的类型,不能直接互相赋值或混合进行算术运算。 - 官方文档 :TypeScript 3.2 - BigInt
创建方式
ts
const largeId = 9007199254740993n;
const orderId = BigInt('9007199254740993');
let total: bigint = 100n;
const fixedTotal: 100n = 100n;
console.log(typeof largeId); // 输出: bigint
- 在整数字面量后添加
n可以创建bigint,如100n。 BigInt()可以把合法的整数或整数字符串转换为bigint。- 对超出安全整数范围的值,优先传入字符串,避免它在进入
BigInt()前已经丢失精度。
ts
const precise = BigInt('9007199254740993');
const alreadyRounded = BigInt(9007199254740993);
console.log(precise); // 输出: 9007199254740993n
console.log(alreadyRounded); // 输出: 9007199254740992n
运算规则
ts
const left = 10n;
const right = 3n;
console.log(left + right); // 输出: 13n
console.log(left / right); // 输出: 3n
console.log(10n < 20); // 输出: true
bigint之间可以进行加、减、乘、除、取余和幂运算。- 除法结果会直接截去小数部分,例如
10n / 3n的结果是3n。 number与bigint可以进行部分关系比较,但不能直接混合进行算术运算。
下面两种写法都会产生类型错误:
ts
let normalValue: number = 100;
let bigValue: bigint = 100n;
normalValue = bigValue;
const result = normalValue + bigValue;
需要先根据业务语义显式转换类型:
ts
const numberResult = 10 + Number(20n);
const bigintResult = BigInt(10) + 20n;
console.log(numberResult); // 输出: 30
console.log(bigintResult); // 输出: 30n
编译与运行环境
使用 100n 这类 bigint 字面量时,tsconfig.json 中的 target 应设置为 ES2020 或更高版本;使用 BigInt() 还需要相应的标准库和运行时支持。
json
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM"]
}
}
注意事项
123.45n是非法写法,因为bigint字面量必须是整数。- 将很大的
bigint转换为number可能丢失精度。 BigInt(1.5)会在运行时抛出错误,因为传入的数值不是整数。- 原生
JSON.stringify()不能直接序列化bigint,需要先转换为字符串或提供自定义序列化逻辑。
string
核心概念
- 定义 :
string表示 JavaScript 中的字符串原始值。 - 写法:可以使用单引号、双引号或模板字符串创建字符串。
- 不可变性:字符串本身不可变,字符串方法会返回新字符串,而不是修改原字符串。
- 官方文档 :The primitives: string, number, and boolean
声明与字符串形式
ts
const singleQuoted = 'TypeScript';
const anotherText = 'JavaScript';
const version = 5;
const templateText = `TypeScript ${version}`;
let message: string = 'hello';
console.log(templateText); // 输出: TypeScript 5
console.log(typeof message); // 输出: string
- 单引号和双引号创建的字符串没有类型差异。
- 模板字符串使用反引号,可以插入表达式,也可以直接书写多行文本。
字符串字面量类型
字符串字面量类型可以把变量限制在明确的字符串集合内:
ts
type RequestMethod = 'GET' | 'POST';
let method: RequestMethod = 'GET';
method = 'POST';
console.log(method); // 输出: POST
这种写法比宽泛的 string 更精确,适合表示状态、操作类型、配置项等有限值。
模板字面量类型
模板字面量不仅能创建字符串值,也能在类型层面组合字符串格式。
ts
type EventName = 'click' | 'change';
type HandlerName = `on${Capitalize<EventName>}`;
const handler: HandlerName = 'onClick';
console.log(handler); // 输出: onClick
HandlerName的结果是'onClick' | 'onChange'。- 官方文档 :Template Literal Types
注意事项
- 日常类型标注应使用
string,不要使用包装对象类型String。 const name = 'Tom'通常推断为字面量类型'Tom';let name = 'Tom'通常会拓宽为string。String(value)可将值转换为字符串;模板字符串中的插值也会触发字符串转换。
类型推断与字面量类型总结
ts
let mutableNumber = 10;
const immutableNumber = 10;
let mutableBigInt = 10n;
const immutableBigInt = 10n;
let mutableString = 'hello';
const immutableString = 'hello';
以上变量通常会被推断为:
| 声明 | 推断类型 |
|---|---|
let mutableNumber = 10 |
number |
const immutableNumber = 10 |
10 |
let mutableBigInt = 10n |
bigint |
const immutableBigInt = 10n |
10n |
let mutableString = 'hello' |
string |
const immutableString = 'hello' |
'hello' |
工作机制 :let 声明的变量可能在后续被重新赋值,因此 TypeScript 通常会将字面量拓宽为对应的基础类型;const 变量不能重新赋值,因此可以保留更精确的字面量类型。
类型转换总结
| 目标类型 | 常用转换方式 | 主要风险 |
|---|---|---|
number |
Number(value) |
无效字符串得到 NaN;大整数可能丢失精度 |
bigint |
BigInt(value) |
小数或非法字符串会抛出错误 |
string |
String(value) |
对象转换结果取决于自身的字符串转换逻辑 |
常见误区
-
误区 :
number只表示小数,整数应该使用其他类型。正确理解 :JavaScript 和 TypeScript 的
number同时表示普通整数与浮点数。 -
误区 :
bigint是范围更大的number,二者可以直接混合计算。正确理解:二者是独立的原始类型,算术运算前必须显式统一类型。
-
误区 :
bigint适合所有高精度计算。正确理解 :
bigint只能精确表示整数,不能直接解决小数精度问题。 -
误区 :
String和string可以在类型标注中随意替换。正确理解 :
string是字符串原始类型,String是包装对象类型,日常开发应使用小写形式。 -
误区 :类型标注能够改变 JavaScript 的运行时行为。
正确理解:TypeScript 类型主要在编译阶段提供检查,最终的数值精度、类型转换和运算行为仍由 JavaScript 决定。