TypeScript Number(超详细)

TypeScript Number 的基础概念与类型定义

在 TypeScript 中,Number 类型是处理数值数据的核心类型之一。它与 JavaScript 的 number 类型基本一致,但 TypeScript 通过静态类型检查,让我们在编码阶段就能发现潜在的数值错误,极大提升了代码的健壮性。

想象一下,Number 类型就像一个“数字容器”——你只能往里面放数字,不能放字符串或布尔值。这种约束在大型项目中尤其重要,避免了“把年龄写成字符串”这类低级错误。

// 声明一个变量为 Number 类型
let age: number = 25;

// 以下代码会报错,因为 TypeScript 检测到类型不匹配
// age = "twenty-five"; // ❌ 类型错误:不能将 string 赋值给 number

注意:TypeScript 会自动推断类型,比如 let price = 99.9,它会自动识别为 number 类型。但为了代码清晰和可维护性,建议显式声明类型。

Number 类型的取值范围与精度问题

Number 类型基于 IEEE 754 标准的 64 位浮点数实现,这意味着它能表示的数值范围大约在 ±1.7976931348623157 × 10³⁰⁸。听起来很大,但实际使用中常遇到精度问题。

举个例子:你可能期望 0.1 + 0.2 等于 0.3,但在计算机中:

// 浮点数精度问题演示
const result = 0.1 + 0.2;
console.log(result); // 输出:0.30000000000000004 ❌

// 这不是 TypeScript 的问题,而是底层数字表示机制决定的

这个问题的本质是:二进制无法精确表示某些十进制小数。就像你用尺子量 1/3 米,永远无法精确到毫米一样。

为解决此类问题,可以使用 Number.EPSILON 来判断两个数是否“足够接近”:

// 判断两个浮点数是否相等(考虑精度误差)
function isEqual(a: number, b: number): boolean {
  return Math.abs(a - b) < Number.EPSILON;
}

console.log(isEqual(0.1 + 0.2, 0.3)); // ✅ 输出 true

常用 Number 类型的方法与属性

TypeScript 的 Number 类型提供了丰富的静态方法和属性,帮助我们更安全地处理数值。

数值转换与类型检查

// 1. isNaN():检查是否为 NaN(非数字)
const invalid = NaN;
console.log(isNaN(invalid)); // ✅ true

// 2. isFinite():检查是否为有限数(排除 Infinity 和 -Infinity)
console.log(isFinite(1 / 0)); // ❌ false,因为 1/0 是 Infinity

// 3. parseInt() 和 parseFloat():从字符串解析数值
const str1 = "123.45";
const str2 = "100px";

console.log(parseInt(str1)); // ✅ 123,只取整数部分
console.log(parseFloat(str2)); // ✅ 100.0,从字符串开头解析数值

数学运算与数值格式化

// 1. Math.round():四舍五入
const price = 99.5;
console.log(Math.round(price)); // ✅ 100

// 2. Math.floor() 和 Math.ceil():向下取整 / 向上取整
console.log(Math.floor(3.7)); // ✅ 3
console.log(Math.ceil(3.2));  // ✅ 4

// 3. toFixed():格式化小数位数(返回字符串)
const amount = 123.456;
console.log(amount.toFixed(2)); // ✅ "123.46",四舍五入到两位小数

⚠️ 注意:toFixed() 返回的是字符串,如果需要数值,需再用 parseFloat() 转换。

数组中的 Number 类型与类型推断

在处理一组数值时,Number 类型常与数组结合使用。TypeScript 提供了强大的类型推断能力。

// 声明一个数值数组
const scores: number[] = [85, 92, 78, 96, 88];

// 使用 forEach 遍历并处理每个数值
scores.forEach((score, index) => {
  // index 是数字索引,score 是数值
  console.log(`第 ${index + 1} 位同学的成绩:${score}`);
});

// 计算平均分
const average = scores.reduce((sum, score) => sum + score, 0) / scores.length;
console.log(`平均分:${average.toFixed(2)}`); // ✅ 输出:88.00

类型推断与泛型

即使不显式声明类型,TypeScript 也能智能推断:

// TypeScript 自动推断为 number[]
const numbers = [1, 2, 3, 4, 5];

// 推断类型为 number,可以安全调用相关方法
numbers.map(n => n * 2); // ✅ 返回 [2, 4, 6, 8, 10]

这种推断机制让代码更简洁,同时保持类型安全。

类型守卫与类型断言在 Number 处理中的应用

在复杂逻辑中,我们可能需要判断某个值是否为合法的 Number 类型。这时,类型守卫和类型断言就派上用场了。

使用类型守卫确保类型安全

// 定义一个函数,安全地处理可能的非数值输入
function processValue(value: unknown): void {
  // 类型守卫:检查是否为 number 类型
  if (typeof value === "number" && !isNaN(value)) {
    console.log(`处理数值:${value}`);
  } else {
    console.log("输入不是有效的数值");
  }
}

// 测试不同输入
processValue(42);        // ✅ 处理数值:42
processValue("42");      // ❌ 输入不是有效的数值
processValue(NaN);       // ❌ 输入不是有效的数值
processValue(null);      // ❌ 输入不是有效的数值

类型断言:明确告诉 TypeScript 你的判断

当你知道某个值一定是 Number 类型,但 TypeScript 无法推断时,可以使用类型断言:

// 假设从表单获取的值是字符串,但你知道它是数字
const userInput = "150";

// 使用类型断言强制转换
const height = Number(userInput) as number;

// 现在 height 被 TypeScript 认为是 number 类型
console.log(height * 2); // ✅ 输出:300

📌 提示:类型断言会绕过类型检查,使用时需确保值确实是目标类型,否则可能导致运行时错误。

实际应用:构建一个简单的计算器

让我们通过一个完整案例,综合运用 Number 类型的核心知识点。

// 简单计算器类
class SimpleCalculator {
  // 存储历史计算记录
  private history: Array<{ op: string; a: number; b: number; result: number }> = [];

  // 计算两个数的和
  add(a: number, b: number): number {
    const result = a + b;
    this.history.push({ op: "+", a, b, result });
    return result;
  }

  // 计算两个数的差
  subtract(a: number, b: number): number {
    const result = a - b;
    this.history.push({ op: "-", a, b, result });
    return result;
  }

  // 计算两个数的乘积
  multiply(a: number, b: number): number {
    const result = a * b;
    this.history.push({ op: "*", a, b, result });
    return result;
  }

  // 计算两个数的商(带除零检查)
  divide(a: number, b: number): number | null {
    if (b === 0) {
      console.error("错误:除数不能为零");
      return null;
    }
    const result = a / b;
    this.history.push({ op: "/", a, b, result });
    return result;
  }

  // 显示计算历史
  showHistory(): void {
    console.log("=== 计算历史 ===");
    this.history.forEach((item, index) => {
      console.log(`${index + 1}. ${item.a} ${item.op} ${item.b} = ${item.result}`);
    });
  }
}

// 使用示例
const calc = new SimpleCalculator();

// 执行一些计算
const sum = calc.add(10, 20);
const diff = calc.subtract(100, 35);
const product = calc.multiply(6, 7);
const quotient = calc.divide(50, 5);

// 显示结果
console.log(`10 + 20 = ${sum}`); // ✅ 30
console.log(`100 - 35 = ${diff}`); // ✅ 65
console.log(`6 × 7 = ${product}`); // ✅ 42
console.log(`50 ÷ 5 = ${quotient}`); // ✅ 10

// 查看历史记录
calc.showHistory();

这个例子展示了 Number 类型在实际项目中的多种用法:参数类型声明、计算逻辑、错误处理、类型安全判断等。

总结与最佳实践

TypeScript Number 类型不仅提供类型安全,还通过丰富的 API 和类型系统,帮助开发者编写更可靠、可维护的代码。关键在于:

  1. 显式声明类型,提升代码可读性;
  2. 注意浮点数精度问题,使用 Number.EPSILONtoFixed() 处理;
  3. 善用类型守卫typeof value === "number")进行安全判断;
  4. 合理使用类型断言,但避免滥用;
  5. 在数组和函数中充分利用类型推断,简化代码。

当你在项目中遇到“数值处理”问题时,不妨先问自己:是否正确使用了 Number 类型?是否考虑了边界情况?这样,你的代码将更加稳健,减少线上事故的发生。