Typescript 的类型

1.number 类型

number 类型包括所有数字:整数、浮点数、正数、负数、Infinity、NaN

在 TypeScript 中,Infinity 是一个特殊的数值表示无穷大。

它通常用来表示一个数值太大,以至于超出了 JavaScript 的数值范围,或者在数学上无法表示的情况。Infinity 是一个全局变量,它的值是正无穷大。

以下是一个示例:

const positiveInfinity = Infinity;
console.log(positiveInfinity); // 输出: Infinity

const negativeInfinity = -Infinity;
console.log(negativeInfinity); // 输出: -Infinity

Infinity 在数学计算中有多种用途,通常用于表示超过任何有限数值的值。在算术运算中,将任何有限数值除以 Infinity 会得到接近零的结果。例如:

const result = 5 / Infinity;
console.log(result); // 输出: 0

注意,Infinity 是一个正数无穷大,而 -Infinity 是负数无穷大。当在计算中涉及到溢出或超出范围的情况时,这些特殊值可以派上用场。

2.bigint(整数大数)

bigint 是 JavaScript 和 TypeScript 中引入的一种数据类型,用于表示任意精度的整数。

number 类型表示的整数最大为 2^53,bigint 比这个数该要大。

与普通的 JavaScript 数字(Number)不同,bigint 可以表示非常大的整数值,而不会丢失精度。在 TypeScript 中,可以使用 bigint 类型来声明和操作这种类型的整数。

以下是一些关于 bigint 的基本信息和示例:

  1. 声明 bigint 类型变量:
const bigIntValue: bigint = 1234567890123456789012345678901234567890n;
  1. 进行算术操作:
const result = bigIntValue + 1n;
console.log(result); // 输出: 1234567890123456789012345678901234567891n
  1. 使用 BigInt 构造函数创建 bigint 值:
const bigIntValue = BigInt("1234567890123456789012345678901234567890");
  1. bigint 支持与普通数字(number)之间的转换:
const regularNumber = 42;
const bigIntValue = BigInt(regularNumber);
const backToNumber = Number(bigIntValue);
  1. 进行比较操作:
const bigInt1 = 100n;
const bigInt2 = 200n;

console.log(bigInt1 < bigInt2); // 输出: true
console.log(bigInt1 === bigInt2); // 输出: false

bigint 对于处理大整数值非常有用,例如在密码学、大数据计算等领域。但要注意,bigint 只能表示整数值,不能表示小数或浮点数。

bigint 的最大值是由可用内存大小所限制的,因为它可以表示非常大的整数值。JavaScript 引擎会根据可用的内存动态调整最大值。

在实际使用中,bigint 的最大值通常比普通 JavaScript 数字(number)的最大值要大得多。普通 JavaScript 数字(number)的最大安全整数可以通过 Number.MAX_SAFE_INTEGER 常量来表示,它的值为 9007199254740991。而 bigint 可以表示远远超过这个范围的整数。

以下是一个示例,演示了bigint 的最大值:

// 尝试创建一个非常大的 bigint
const veryLargeBigInt =
  BigInt(Number.MAX_SAFE_INTEGER) * BigInt(Number.MAX_SAFE_INTEGER);
console.log(veryLargeBigInt.toString());

// 你可以继续增加倍数,bigint 不受 JavaScript 数字的限制
const evenLargerBigInt = veryLargeBigInt * veryLargeBigInt;
console.log(evenLargerBigInt.toString());

请注意,虽然 bigint 可以表示非常大的整数值,但它们的计算成本可能会很高,尤其是对于非常大的值。因此,在使用 bigint 处理大整数时,需要考虑性能和内存消耗。

3.unique symbol(唯一符号)

3.1 unique symbol 类型

在 TypeScript 中,Unique Symbol(唯一符号)是一种特殊的数据类型,用于创建独一无二的符号值。唯一符号通常用于创建私有属性或键,以确保其不会与其他属性或键发生冲突。

唯一符号通过Symbol函数创建,但是要使用unique symbol类型注释来确保其唯一性。例如:

const uniqueSymbol: unique symbol = Symbol("unique description");

这里的unique symbol类型注释告诉 TypeScript,uniqueSymbol 是一个唯一符号,不同于其他符号。

唯一符号的主要用途之一是在对象上创建私有属性或键,因为唯一符号无法通过常规代码访问。例如:

const myObject = {
  [uniqueSymbol]: "This is a private property",
};

console.log(myObject[uniqueSymbol]); // 正确,可以访问
console.log(myObject); // 错误,无法直接访问唯一符号

这样,uniqueSymbol 成为对象的私有属性,只能通过知道该唯一符号的代码来访问它。这有助于避免属性名冲突和不必要的暴露。

3.2 Symbol 与 unique symbol 差异

Symbolunique symbol 都是 JavaScript 和 TypeScript 中用于创建符号值的构造函数,但它们之间有一些重要的区别:

  1. 唯一性:

    • Symbol: 创建的符号是唯一的,但可以通过不同的 Symbol 调用创建具有相同描述的多个符号,这些符号在逻辑上是不同的。
    • unique symbol: 创建的符号是完全唯一的,不能通过其他方法创建具有相同描述的唯一符号。这确保了它们的绝对唯一性。
  2. 类型:

    • Symbol 的类型是 symbol,可以用作属性键或对象属性的描述符。
    • unique symbol 的类型是 unique symbol,是 TypeScript 特有的类型注释,用于指示一个符号是唯一的。
  3. 使用场景:

    • Symbol 常用于创建不同的属性键,以防止属性名冲突。
    • unique symbol 主要用于创建私有属性或键,确保这些属性无法通过常规手段访问。

示例:

const symbol1 = Symbol("description");
const symbol2 = Symbol("description");
console.log(symbol1 === symbol2); // false,不同的Symbol

const uniqueSymbol1: unique symbol = Symbol("description");
const uniqueSymbol2: unique symbol = Symbol("description");
// TypeScript会报错,因为唯一符号不能创建多个相同描述的符号

总之,unique symbol 是 TypeScript 的扩展,用于确保符号的绝对唯一性,特别适用于创建私有属性或键,而普通的 Symbol 则用于一般的符号需求。

4.泛型

4.1 泛型的理解

泛型(Generics)是 TypeScript 中强大而灵活的特性,它允许你编写可重用、类型安全的代码,同时在不同类型之间保持抽象性。 理解 TypeScript 的泛型可以帮助你更好地处理不同数据类型的需求,提高代码的可维护性和安全性。

以下是一些关键概念来理解 TypeScript 的泛型:

  1. 泛型类型参数(Type Parameters): 泛型允许你在函数、类或接口中定义参数或成员,这些参数可以代表任何类型,通常用单个字母(如 T)表示。这些类型参数在函数或类定义中充当占位符,稍后可以由具体的类型替代。

  2. 类型变量(Type Variables): 类型参数在定义中表示的是类型变量。这些类型变量不会被编译为实际代码,而是在编译时被替换为实际类型。这使得你能够编写通用的代码,适应多种数据类型。

  3. 类型安全: 泛型提供了类型安全的方式来处理不同类型的数据,避免了在运行时出现类型错误。编译器能够检查泛型类型是否符合预期,从而提前发现并修复潜在的错误。

  4. 重用性: 泛型使你能够编写通用的函数、类或接口,以处理不同类型的数据,而不需要为每种类型编写重复的代码。这增加了代码的重用性,减少了代码冗余。

  5. 范围广泛: 泛型可以用于函数、类、接口,甚至用于定义复杂的数据结构,如数组、元组、映射等。

示例:

// 使用泛型函数,T代表类型参数
function identity<T>(arg: T): T {
  return arg;
}

// 使用泛型类
class GenericClass<T> {
  private value: T;
  constructor(value: T) {
    this.value = value;
  }
  getValue(): T {
    return this.value;
  }
}

// 使用泛型接口
interface KeyValuePair<T, U> {
  key: T;
  value: U;
}

// 泛型数组
const numbers: Array<number> = [1, 2, 3, 4, 5];

在上述示例中,T 是一个类型参数,它可以代表任何类型。泛型函数 identity 可以接受任意类型的参数并返回相同类型的值。泛型类 GenericClass 和泛型接口 KeyValuePair 也演示了如何使用泛型来处理不同类型的数据。

4.2 泛型使用

TypeScript 的泛型用法:

  1. 类型变量(Type Variables): 泛型中使用的类型参数通常以大写字母开头,如 TU 等。这些类型参数可以代表任何类型,类似于函数参数的占位符。

  2. 泛型函数: 泛型函数是具有类型参数的函数,允许在函数定义中使用这些类型参数。以下是一个示例:

    function identity<T>(arg: T): T {
      return arg;
    }
    
    // 使用泛型函数
    let result = identity("Hello, TypeScript"); // result的类型为string
    

    这个函数 identity 可以接受任何类型的参数,并返回相同类型的值。

  3. 泛型类: 类也可以是泛型的。你可以在类定义中使用类型参数来创建泛型类。以下是一个示例:

    class GenericClass<T> {
      private value: T;
      constructor(value: T) {
        this.value = value;
      }
      getValue(): T {
        return this.value;
      }
    }
    
    // 使用泛型类
    let strGeneric = new GenericClass("Hello, Generics");
    let numGeneric = new GenericClass(42);
    

    这个泛型类 GenericClass 允许你在实例化时指定数据类型。

  4. 泛型接口: 你可以定义泛型接口,使接口的属性或方法可以处理不同类型的数据。以下是一个示例:

    interface Pair<T, U> {
      first: T;
      second: U;
    }
    
    // 使用泛型接口
    let pair: Pair<number, string> = { first: 1, second: "two" };
    

    这个泛型接口 Pair 定义了两个属性,firstsecond,每个属性都可以是不同的数据类型。

  5. 泛型约束(Generic Constraints): 有时你可能需要对泛型进行更精确的控制。你可以使用泛型约束来指定类型参数必须具有某些属性或方法。这有助于确保你可以在泛型函数或类中访问特定属性或方法,而不仅仅是任意类型。以下是一个示例:

    interface Lengthwise {
      length: number;
    }
    
    function getLength<T extends Lengthwise>(arg: T): number {
      return arg.length;
    }
    
    // 使用泛型约束
    let strLength = getLength("Hello"); // 正确,strLength为5
    let arrayLength = getLength([1, 2, 3]); // 正确,arrayLength为3
    let numLength = getLength(42); // 错误,数字没有length属性
    

    在这个示例中,getLength 函数使用泛型约束,要求传入的参数必须具有 length 属性,这样可以安全地获取其长度。

泛型是 TypeScript 强大而灵活的功能,可以帮助你编写更通用、类型安全的代码,同时减少重复性的工作。它在函数、类、接口等各种上下文中都能派上用场,让你更好地处理不同数据类型的需求。

Contributors: masecho