TypeScript基础:数字类型和字符串类型的转换

TypeScript 基础:数字类型和字符串类型的转换详解

在 TypeScript(以及 JavaScript)的开发中,数字(Number)和字符串(String)是最基础也是最常用的两种数据类型。由于 JavaScript 的弱类型特性,以及 TypeScript 对类型安全的追求,我们经常需要在数字和字符串之间进行转换。理解这些转换的机制和方法,对于编写健壮、可维护的代码至关重要。本文将深入探讨 TypeScript 中数字和字符串类型之间的各种转换方式,包括隐式转换、显式转换、以及一些常见的陷阱和最佳实践。

一、 TypeScript 中的数字类型

TypeScript 遵循 JavaScript 的规范,所有数字都是以 64 位浮点数的形式存储的,没有单独的整数类型。这意味着 TypeScript 中的 number 类型既可以表示整数,也可以表示小数。

typescript
let integer: number = 10;
let decimal: number = 3.14;
let hex: number = 0xff; // 十六进制
let binary: number = 0b1010; // 二进制
let octal: number = 0o755; // 八进制
let bigInt: bigint = 100n; //大整数,注意与number类型的区别

尽管 JavaScript(以及 TypeScript)中没有明确的整数类型,但在进行位运算时,数字会被视为 32 位有符号整数。

二、 TypeScript 中的字符串类型

TypeScript 中的字符串类型 string 用于表示文本数据。字符串可以用单引号(')、双引号(")或反引号(`)表示。

typescript
let singleQuoted: string = 'Hello';
let doubleQuoted: string = "World";
let templateLiteral: string = `Hello, ${singleQuoted}!`; // 模板字符串

模板字符串(使用反引号)允许嵌入表达式,这使得字符串拼接更加方便。

三、 隐式类型转换 (Implicit Type Coercion)

在某些情况下,TypeScript(和 JavaScript)会自动进行类型转换,这称为隐式类型转换。对于数字和字符串,最常见的隐式转换发生在以下几种情况:

  1. 加号 (+) 运算符:

    • 如果 + 运算符的一个操作数是字符串,那么另一个操作数也会被转换为字符串,然后进行字符串拼接。
    • 如果 + 运算符的两个操作数都是数字,那么会进行数值加法运算。

    ```typescript
    let num = 10;
    let str = "20";

    let result1 = num + str; // "1020" (字符串拼接)
    let result2 = num + Number(str); // 30 (数值加法,先显式转换)
    let result3 = num + +str; //30 (数值加法,+str是一元加运算符)
    let result4 = "hello" + 20 + 24 //"hello2024"
    let result5 = 20 + 24 + "hello" //"44hello"
    ```

    一元加运算符具有将字符串转为数字的功能。

  2. 其他算术运算符:

    除了 + 运算符外,其他算术运算符(-*/%)都会尝试将操作数转换为数字。如果转换失败,结果将是 NaN (Not a Number)。

    ```typescript
    let str = "20";

    let result1 = str - 5; // 15 (字符串 "20" 被转换为数字 20)
    let result2 = str * 2; // 40 (字符串 "20" 被转换为数字 20)
    let result3 = str / 4; // 5 (字符串 "20" 被转换为数字 20)
    let result4 = str % 3; // 2 (字符串 "20" 被转换为数字 20)
    let result5 = "abc" - 5;// NaN
    ```

  3. 比较运算符:

    比较运算符(==!=><>=<=)在进行比较时,如果操作数类型不同,也会发生隐式类型转换。但是,==!= 的隐式转换规则比较复杂,容易出错,因此通常建议使用严格相等运算符(===!==),它们不会进行类型转换。

  4. 逻辑运算符:
    当使用逻辑运算符(如 &&||!)时,操作数会被转换为布尔值。对于数字和字符串,转换规则如下:

    • 数字: 0、-0、NaN 会被转换为 false,其他数字会被转换为 true
    • 字符串: 空字符串("")会被转换为 false,其他字符串会被转换为 true

    ```typescript
    let num1 = 0;
    let num2 = 10;
    let str1 = "";
    let str2 = "hello";

    console.log(!!num1); // false
    console.log(!!num2); // true
    console.log(!!str1); // false
    console.log(!!str2); // true

    ```

隐式转换的风险: 隐式转换虽然方便,但有时会产生意想不到的结果。例如:

typescript
console.log("1" + 2 + 3); // "123"
console.log(1 + 2 + "3"); // "33"

由于 + 运算符的结合性是从左到右,第一个例子中 "1" + 2 变成了字符串拼接,结果是 "12",然后再与 3 拼接。第二个例子中 1 + 2 是数值加法,结果是 3,然后再与 "3" 拼接。

为了避免这种混乱,强烈建议在进行数字和字符串运算时使用显式类型转换。

四、 显式类型转换 (Explicit Type Conversion)

显式类型转换是指通过明确的函数调用或运算符来将一个类型转换为另一个类型。

1. 将字符串转换为数字

有几种方法可以将字符串转换为数字:

  • Number() 函数: 这是最常用的方法,它可以将字符串转换为数字。如果字符串不能解析为有效的数字,则返回 NaN

    ```typescript
    let str1 = "123";
    let str2 = "3.14";
    let str3 = "abc";
    let str4 = " 123 ";

    let num1 = Number(str1); // 123
    let num2 = Number(str2); // 3.14
    let num3 = Number(str3); // NaN
    let num4 = Number(str4); // 123 (会忽略首尾空格)
    ```

  • parseInt() 函数: parseInt() 函数用于将字符串解析为整数。它可以指定进制(基数),如果没有指定,则默认为十进制。如果字符串不能解析为整数,则返回 NaNparseInt() 会忽略字符串开头的空格,并从第一个非空格字符开始解析,直到遇到非数字字符为止。

    ```typescript
    let str1 = "123";
    let str2 = "3.14";
    let str3 = "abc";
    let str4 = " 123 ";
    let str5 = "123px";
    let str6 = "0xff";

    let num1 = parseInt(str1); // 123
    let num2 = parseInt(str2); // 3 (小数部分被截断)
    let num3 = parseInt(str3); // NaN
    let num4 = parseInt(str4); // 123 (忽略首尾空格)
    let num5 = parseInt(str5); // 123 (遇到 "px" 停止解析)
    let num6 = parseInt(str6); // 0 (默认十进制,"0x" 不表示十六进制)
    let num7 = parseInt(str6, 16); // 255 (指定十六进制)
    ```

  • parseFloat() 函数: parseFloat() 函数用于将字符串解析为浮点数。它与 parseInt() 类似,但可以解析小数部分。

    ```typescript
    let str1 = "123";
    let str2 = "3.14";
    let str3 = "abc";
    let str4 = " 123.45 ";
    let str5 = "3.14e7"; //科学计数法

    let num1 = parseFloat(str1); // 123
    let num2 = parseFloat(str2); // 3.14
    let num3 = parseFloat(str3); // NaN
    let num4 = parseFloat(str4); // 123.45 (忽略首尾空格)
    let num5 = parseFloat(str5); //31400000
    ```

  • 一元加运算符 (+): 将字符串放在 + 运算符后面,可以将其转换为数字。这种方法与 Number() 函数的效果相同。

    typescript
    let str = "123";
    let num = +str; // 123

2. 将数字转换为字符串

将数字转换为字符串也有几种方法:

  • String() 函数: 这是最常用的方法,它可以将任何类型的值转换为字符串。

    typescript
    let num = 123;
    let str = String(num); // "123"

  • toString() 方法: 所有 JavaScript 对象(包括数字)都有 toString() 方法,它可以将对象转换为字符串。对于数字,toString() 方法可以接受一个可选的参数,表示进制(基数)。

    typescript
    let num = 123;
    let str1 = num.toString(); // "123" (默认十进制)
    let str2 = num.toString(2); // "1111011" (二进制)
    let str3 = num.toString(16); // "7b" (十六进制)

  • 字符串拼接: 将数字与空字符串("")拼接,可以将其转换为字符串。这是因为 + 运算符的隐式转换规则。

    typescript
    let num = 123;
    let str = num + ""; // "123"

  • 模板字符串
    typescript
    let num = 123;
    let str = `${num}` // "123"

五、 常见陷阱和最佳实践

  1. 避免使用 ==!= 进行数字和字符串的比较: 由于 ==!= 的隐式转换规则复杂,容易出错,应该使用 ===!== 进行严格比较。

  2. 明确使用显式类型转换: 为了代码的可读性和可维护性,尽量避免依赖隐式类型转换,而是使用 Number()parseInt()parseFloat()String()toString() 等函数进行显式转换。

  3. 处理 NaN 当字符串无法转换为数字时,Number()parseInt()parseFloat() 会返回 NaNNaN 是一个特殊的数字值,它不等于任何值,包括它自己。要检查一个值是否是 NaN,应该使用 isNaN() 函数。

    ```typescript
    let str = "abc";
    let num = Number(str); // NaN

    console.log(num === NaN); // false (NaN 不等于任何值,包括自身)
    console.log(isNaN(num)); // true
    ```

  4. 使用 parseInt() 时指定进制: 为了避免意外的错误,建议在使用 parseInt() 时始终指定进制(第二个参数)。

  5. 注意 toString() 的进制参数: Number.prototype.toString()的进制参数是可选的。在没有指定进制时默认为10进制,这一点很容易被忽视。

  6. 使用 TypeScript 的类型注解: 利用 TypeScript 的类型注解,可以减少类型相关的错误。例如,如果你知道一个变量应该是数字,就应该明确地声明它的类型为 number

    typescript
    let num: number = parseInt("123"); // 明确声明 num 为 number 类型

  7. 使用工具函数: 可以创建一些工具函数来封装常见的类型转换逻辑,提高代码的复用性和可读性。

    ```typescript
    function parseNumber(str: string, defaultValue: number = 0): number {
    const num = Number(str);
    return isNaN(num) ? defaultValue : num;
    }

    let num1 = parseNumber("123"); // 123
    let num2 = parseNumber("abc", 10); // 10
    let num3 = parseNumber("abc"); // 0
    ```

六、 总结

数字和字符串类型之间的转换是 TypeScript 编程中的基础操作。理解隐式转换和显式转换的机制,以及各种转换函数的用法,对于编写可靠、可维护的代码至关重要。通过遵循最佳实践,例如避免使用 ==!=、明确使用显式类型转换、处理 NaN、使用 TypeScript 的类型注解等,可以减少类型相关的错误,提高代码质量。

THE END