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
的基本信息和示例:
- 声明
bigint
类型变量:
const bigIntValue: bigint = 1234567890123456789012345678901234567890n;
- 进行算术操作:
const result = bigIntValue + 1n;
console.log(result); // 输出: 1234567890123456789012345678901234567891n
- 使用
BigInt
构造函数创建bigint
值:
const bigIntValue = BigInt("1234567890123456789012345678901234567890");
bigint
支持与普通数字(number
)之间的转换:
const regularNumber = 42;
const bigIntValue = BigInt(regularNumber);
const backToNumber = Number(bigIntValue);
- 进行比较操作:
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 差异
Symbol
和 unique symbol
都是 JavaScript 和 TypeScript 中用于创建符号值的构造函数,但它们之间有一些重要的区别:
唯一性:
Symbol
: 创建的符号是唯一的,但可以通过不同的Symbol
调用创建具有相同描述的多个符号,这些符号在逻辑上是不同的。unique symbol
: 创建的符号是完全唯一的,不能通过其他方法创建具有相同描述的唯一符号。这确保了它们的绝对唯一性。
类型:
Symbol
的类型是symbol
,可以用作属性键或对象属性的描述符。unique symbol
的类型是unique symbol
,是 TypeScript 特有的类型注释,用于指示一个符号是唯一的。
使用场景:
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 的泛型:
泛型类型参数(Type Parameters): 泛型允许你在函数、类或接口中定义参数或成员,这些参数可以代表任何类型,通常用单个字母(如
T
)表示。这些类型参数在函数或类定义中充当占位符,稍后可以由具体的类型替代。类型变量(Type Variables): 类型参数在定义中表示的是类型变量。这些类型变量不会被编译为实际代码,而是在编译时被替换为实际类型。这使得你能够编写通用的代码,适应多种数据类型。
类型安全: 泛型提供了类型安全的方式来处理不同类型的数据,避免了在运行时出现类型错误。编译器能够检查泛型类型是否符合预期,从而提前发现并修复潜在的错误。
重用性: 泛型使你能够编写通用的函数、类或接口,以处理不同类型的数据,而不需要为每种类型编写重复的代码。这增加了代码的重用性,减少了代码冗余。
范围广泛: 泛型可以用于函数、类、接口,甚至用于定义复杂的数据结构,如数组、元组、映射等。
示例:
// 使用泛型函数,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 的泛型用法:
类型变量(Type Variables): 泛型中使用的类型参数通常以大写字母开头,如
T
,U
等。这些类型参数可以代表任何类型,类似于函数参数的占位符。泛型函数: 泛型函数是具有类型参数的函数,允许在函数定义中使用这些类型参数。以下是一个示例:
function identity<T>(arg: T): T { return arg; } // 使用泛型函数 let result = identity("Hello, TypeScript"); // result的类型为string
这个函数
identity
可以接受任何类型的参数,并返回相同类型的值。泛型类: 类也可以是泛型的。你可以在类定义中使用类型参数来创建泛型类。以下是一个示例:
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
允许你在实例化时指定数据类型。泛型接口: 你可以定义泛型接口,使接口的属性或方法可以处理不同类型的数据。以下是一个示例:
interface Pair<T, U> { first: T; second: U; } // 使用泛型接口 let pair: Pair<number, string> = { first: 1, second: "two" };
这个泛型接口
Pair
定义了两个属性,first
和second
,每个属性都可以是不同的数据类型。泛型约束(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 强大而灵活的功能,可以帮助你编写更通用、类型安全的代码,同时减少重复性的工作。它在函数、类、接口等各种上下文中都能派上用场,让你更好地处理不同数据类型的需求。