《TypeScript全面指南》第七章:TypeScript 的 symbol 类型

748 阅读4分钟

简介

symbol 是 ECMAScript 2015(也称为 ES6)引入的一个新的原始数据类型。它主要用于创建对象的唯一属性名。在 TypeScript 中,你可以使用 symbol 类型来确保对象属性的唯一性,以及其他与符号相关的操作。

与其他原始类型(如 numberstring)不同,symbol 是不可变的且唯一的

创建 symbol 类型的值:

let sym1 = Symbol();
let sym2 = Symbol("key"); // 可选的字符串key

unique symbol

在 TypeScript 中,有一种特殊的 symbol 类型,称为 unique symbol。这种类型的符号是通过 Symbol()Symbol.for() 构造器创建的,并且使用 const 声明。使用 unique symbol 类型可以确保一个符号永远不会与其他任何符号值相等。

const symUnique: unique symbol = Symbol();

这意味着,如果你试图将其他任何 symbol 值赋给 symUnique,TypeScript 将会抛出一个类型错误。

类型推断

在 TypeScript 中,当你使用 Symbol() 构造函数创建一个新的符号时,TypeScript 将自动为其推断 symbol 类型。

let sym = Symbol();
// TypeScript understands 'sym' is of type 'symbol'

但是,当使用 const 关键字与 unique symbol 类型声明一个符号时,TypeScript 将为其推断一个特定的唯一符号类型。

const uniqueSym: unique symbol = Symbol();
// TypeScript understands 'uniqueSym' is of a unique symbol type

这种类型推断使得符号的使用在 TypeScript 中更加类型安全,因为它可以确保你不会意外地用其他符号值替换一个 unique symbol

unique symbolsymbol 的区别

symbolunique symbol 都是 TypeScript 中的数据类型,它们都代表唯一的、不可变的数据值,但它们之间有一些关键的区别:

  1. 创建方式:

    • symbol: 可以通过 Symbol()Symbol.for() 创建。
    • unique symbol: 只能通过 Symbol() 创建,并且必须使用 const 声明。
  2. 唯一性:

    • symbol: 虽然通过 Symbol() 创建的每个符号都是唯一的,但 symbol 类型的变量可以被任何 symbol 值赋值。
    • unique symbol: 一旦为 unique symbol 类型的变量赋值,该变量不能被其他任何 symbol 值重新赋值。这确保了其绝对的唯一性。
  3. 类型安全性:

    • symbol: 提供了一定的类型安全性,因为符号是唯一的。
    • unique symbol: 提供了更强的类型安全性,因为尝试将其他 symbol 值赋给 unique symbol 类型的变量会导致 TypeScript 抛出类型错误。
  4. 使用场景:

    • symbol: 通常用于创建对象的唯一属性键,以避免属性名冲突。
    • unique symbol: 当你需要确保某个符号值绝对不会与其他任何符号值相等时,例如在创建单例模式或特定的唯一标识符时。

总之,unique symbolsymbol 的一个更加严格的子类型,它提供了更强的唯一性和类型安全性。

Symbol()Symbol.for()

Symbol()Symbol.for() 都是用于创建符号的方法,但它们的工作方式和用途略有不同。以下是如何使用这两种方法创建符号的详细说明:

1. 使用 Symbol()

Symbol() 创建一个新的、唯一的符号值。你可以为它提供一个可选的描述字符串,但这个描述只是为了调试目的,不能用于访问符号。

示例:

const sym1 = Symbol();
const sym2 = Symbol('description');

console.log(sym1); // Symbol()
console.log(sym2); // Symbol(description)

注意:即使两个符号有相同的描述,它们也是不相等的。

const sym3 = Symbol('test');
const sym4 = Symbol('test');

console.log(sym3 === sym4); // false

2. 使用 Symbol.for()

Symbol.for() 会首先检查是否存在一个与给定键关联的符号在全局符号注册表中。如果存在,它会返回该符号;否则,它会创建一个新的符号并将其与该键关联。

示例:

const sym5 = Symbol.for('example');
const sym6 = Symbol.for('example');

console.log(sym5); // Symbol(example)
console.log(sym6); // Symbol(example)
console.log(sym5 === sym6); // true

在上面的示例中,sym5sym6 都是使用相同的键 "example" 通过 Symbol.for() 创建的。因为它们都引用全局符号注册表中的同一个符号,所以它们是相等的。

总结:

  • 使用 Symbol() 创建的每个符号都是唯一的。
  • 使用 Symbol.for() 创建的符号可能不是唯一的,因为它会首先尝试从全局符号注册表中检索符号。

选择哪种方法取决于你的具体需求。如果你需要一个确保唯一的符号,使用 Symbol()。如果你需要跨多个执行上下文共享符号,使用 Symbol.for()

总结

symbol 类型在 JavaScript 和 TypeScript 中为开发者提供了创建不可变、唯一键值的能力,这对于避免命名冲突和与私有属性相关的其他用途特别有用。而 TypeScript 的类型系统进一步增强了与 symbol 相关的类型安全性,特别是引入了 unique symbol 这一概念。