isSymbol
检查值是否为Symbol类型。
基础用法
typescript
import { isSymbol } from 'radash'
console.log(isSymbol(Symbol('test'))) // true
console.log(isSymbol(Symbol())) // true
console.log(isSymbol(Symbol.iterator)) // true
console.log(isSymbol('symbol')) // false
console.log(isSymbol(123)) // false
console.log(isSymbol({})) // false
语法
typescript
function isSymbol(value: any): value is symbol
参数
value
(any): 要检查的值
返回值
返回一个布尔值,如果值是Symbol则返回 true
,否则返回 false
。同时作为TypeScript类型守卫。
示例
基本类型检查
typescript
import { isSymbol } from 'radash'
// Symbol类型
console.log(isSymbol(Symbol('test'))) // true
console.log(isSymbol(Symbol())) // true
console.log(isSymbol(Symbol.iterator)) // true
console.log(isSymbol(Symbol.asyncIterator)) // true
console.log(isSymbol(Symbol.toStringTag)) // true
console.log(isSymbol(Symbol.toPrimitive)) // true
// 非Symbol类型
console.log(isSymbol('symbol')) // false
console.log(isSymbol(123)) // false
console.log(isSymbol(true)) // false
console.log(isSymbol(null)) // false
console.log(isSymbol(undefined)) // false
console.log(isSymbol({})) // false
console.log(isSymbol([])) // false
console.log(isSymbol(() => {})) // false
内置Symbol检查
typescript
import { isSymbol } from 'radash'
// 内置Symbol
console.log(isSymbol(Symbol.iterator)) // true
console.log(isSymbol(Symbol.asyncIterator)) // true
console.log(isSymbol(Symbol.toStringTag)) // true
console.log(isSymbol(Symbol.toPrimitive)) // true
console.log(isSymbol(Symbol.unscopables)) // true
console.log(isSymbol(Symbol.species)) // true
console.log(isSymbol(Symbol.split)) // true
console.log(isSymbol(Symbol.match)) // true
console.log(isSymbol(Symbol.replace)) // true
console.log(isSymbol(Symbol.search)) // true
console.log(isSymbol(Symbol.hasInstance)) // true
console.log(isSymbol(Symbol.isConcatSpreadable)) // true
类型守卫使用
typescript
import { isSymbol } from 'radash'
function processValue(value: unknown) {
if (isSymbol(value)) {
// TypeScript 知道 value 是 Symbol
console.log('Processing Symbol:', value.toString())
return value.toString()
}
console.log('Processing non-Symbol:', typeof value)
return String(value)
}
const symbol = Symbol('test')
const string = 'hello'
console.log(processValue(symbol)) // Processing Symbol: Symbol(test) Symbol(test)
console.log(processValue(string)) // Processing non-Symbol: string hello
数组过滤
typescript
import { isSymbol } from 'radash'
const mixedArray = [
Symbol('test1'),
'hello',
123,
Symbol('test2'),
Symbol.iterator,
{},
[],
() => {},
Symbol('test3')
]
const symbols = mixedArray.filter(isSymbol)
console.log(symbols.length) // 4
const nonSymbols = mixedArray.filter(item => !isSymbol(item))
console.log(nonSymbols.length) // 5
对象属性检查
typescript
import { isSymbol } from 'radash'
const data = {
[Symbol('id')]: 1,
name: 'Alice',
[Symbol('secret')]: 'hidden',
age: 25,
[Symbol.iterator]: function* () { yield 1; yield 2; }
}
const symbolProperties = Object.getOwnPropertySymbols(data)
.filter(symbol => isSymbol(symbol))
.map(symbol => ({ key: symbol.toString(), value: data[symbol] }))
console.log(symbolProperties)
// [
// { key: 'Symbol(id)', value: 1 },
// { key: 'Symbol(secret)', value: 'hidden' },
// { key: 'Symbol(Symbol.iterator)', value: [GeneratorFunction] }
// ]
Symbol注册表
typescript
import { isSymbol } from 'radash'
class SymbolRegistry {
private symbols = new Map<string, symbol>()
getSymbol(key: string): symbol {
if (!this.symbols.has(key)) {
this.symbols.set(key, Symbol(key))
}
return this.symbols.get(key)!
}
getAllSymbols(): symbol[] {
return Array.from(this.symbols.values()).filter(isSymbol)
}
hasSymbol(key: string): boolean {
const symbol = this.symbols.get(key)
return symbol !== undefined && isSymbol(symbol)
}
}
const registry = new SymbolRegistry()
const idSymbol = registry.getSymbol('id')
const nameSymbol = registry.getSymbol('name')
const ageSymbol = registry.getSymbol('age')
console.log(registry.hasSymbol('id')) // true
console.log(registry.getAllSymbols()) // [Symbol(id), Symbol(name), Symbol(age)]
元数据管理
typescript
import { isSymbol } from 'radash'
class MetadataManager {
private metadata = new WeakMap<object, Map<symbol, any>>()
setMetadata<T>(target: object, key: symbol, value: T): void {
if (!isSymbol(key)) {
throw new Error('Key must be a Symbol')
}
if (!this.metadata.has(target)) {
this.metadata.set(target, new Map())
}
this.metadata.get(target)!.set(key, value)
}
getMetadata<T>(target: object, key: symbol): T | undefined {
if (!isSymbol(key)) {
return undefined
}
const targetMetadata = this.metadata.get(target)
return targetMetadata?.get(key)
}
getSymbolKeys(target: object): symbol[] {
const targetMetadata = this.metadata.get(target)
if (!targetMetadata) return []
return Array.from(targetMetadata.keys()).filter(isSymbol)
}
}
const metadata = new MetadataManager()
const user = { name: 'Alice', age: 25 }
const idSymbol = Symbol('id')
const secretSymbol = Symbol('secret')
metadata.setMetadata(user, idSymbol, 12345)
metadata.setMetadata(user, secretSymbol, 'top secret')
console.log(metadata.getMetadata(user, idSymbol)) // 12345
console.log(metadata.getMetadata(user, secretSymbol)) // top secret
console.log(metadata.getSymbolKeys(user)) // [Symbol(id), Symbol(secret)]
私有属性模拟
typescript
import { isSymbol } from 'radash'
class PrivateClass {
private [Symbol('privateField')] = 'private value'
private [Symbol('privateMethod')] = () => 'private method'
publicField = 'public value'
getPrivateField(): string {
const symbols = Object.getOwnPropertySymbols(this).filter(isSymbol)
const privateFieldSymbol = symbols.find(s => s.toString().includes('privateField'))
return privateFieldSymbol ? this[privateFieldSymbol] : 'not found'
}
callPrivateMethod(): string {
const symbols = Object.getOwnPropertySymbols(this).filter(isSymbol)
const privateMethodSymbol = symbols.find(s => s.toString().includes('privateMethod'))
return privateMethodSymbol ? this[privateMethodSymbol]() : 'not found'
}
}
const instance = new PrivateClass()
console.log(instance.getPrivateField()) // private value
console.log(instance.callPrivateMethod()) // private method
console.log(instance.publicField) // public value
迭代器实现
typescript
import { isSymbol } from 'radash'
class CustomCollection {
private items: any[] = []
[Symbol.iterator]() {
let index = 0
return {
next: () => {
if (index < this.items.length) {
return { value: this.items[index++], done: false }
}
return { value: undefined, done: true }
}
}
}
add(item: any) {
this.items.push(item)
}
getIteratorSymbol(): symbol | null {
const symbols = Object.getOwnPropertySymbols(this).filter(isSymbol)
return symbols.find(s => s === Symbol.iterator) || null
}
}
const collection = new CustomCollection()
collection.add('a')
collection.add('b')
collection.add('c')
console.log(collection.getIteratorSymbol()) // Symbol(Symbol.iterator)
for (const item of collection) {
console.log(item) // a, b, c
}
类型检查工具
typescript
import { isSymbol } from 'radash'
class TypeChecker {
static getSymbolProperties(obj: object): symbol[] {
return Object.getOwnPropertySymbols(obj).filter(isSymbol)
}
static hasSymbolProperty(obj: object, symbol: symbol): boolean {
return isSymbol(symbol) && Object.getOwnPropertySymbols(obj).includes(symbol)
}
static getSymbolValue<T>(obj: object, symbol: symbol): T | undefined {
if (!isSymbol(symbol) || !this.hasSymbolProperty(obj, symbol)) {
return undefined
}
return obj[symbol]
}
}
const testObj = {
[Symbol('id')]: 123,
[Symbol('name')]: 'test',
regularProp: 'value'
}
console.log(TypeChecker.getSymbolProperties(testObj)) // [Symbol(id), Symbol(name)]
console.log(TypeChecker.hasSymbolProperty(testObj, Symbol('id'))) // true
console.log(TypeChecker.getSymbolValue(testObj, Symbol('id'))) // 123
配置管理
typescript
import { isSymbol } from 'radash'
class ConfigManager {
private config = new Map<symbol, any>()
setConfig(key: symbol, value: any): void {
if (!isSymbol(key)) {
throw new Error('Config key must be a Symbol')
}
this.config.set(key, value)
}
getConfig<T>(key: symbol): T | undefined {
if (!isSymbol(key)) {
return undefined
}
return this.config.get(key)
}
getAllSymbolKeys(): symbol[] {
return Array.from(this.config.keys()).filter(isSymbol)
}
hasConfig(key: symbol): boolean {
return isSymbol(key) && this.config.has(key)
}
}
const config = new ConfigManager()
const apiKeySymbol = Symbol('apiKey')
const timeoutSymbol = Symbol('timeout')
const debugSymbol = Symbol('debug')
config.setConfig(apiKeySymbol, 'secret-key-123')
config.setConfig(timeoutSymbol, 5000)
config.setConfig(debugSymbol, true)
console.log(config.getConfig(apiKeySymbol)) // secret-key-123
console.log(config.getConfig(timeoutSymbol)) // 5000
console.log(config.hasConfig(debugSymbol)) // true
console.log(config.getAllSymbolKeys()) // [Symbol(apiKey), Symbol(timeout), Symbol(debug)]
事件系统
typescript
import { isSymbol } from 'radash'
class EventEmitter {
private events = new Map<symbol, Function[]>()
on(event: symbol, handler: Function): void {
if (!isSymbol(event)) {
throw new Error('Event must be a Symbol')
}
if (!this.events.has(event)) {
this.events.set(event, [])
}
this.events.get(event)!.push(handler)
}
emit(event: symbol, ...args: any[]): void {
if (!isSymbol(event) || !this.events.has(event)) {
return
}
this.events.get(event)!.forEach(handler => handler(...args))
}
getSymbolEvents(): symbol[] {
return Array.from(this.events.keys()).filter(isSymbol)
}
}
const emitter = new EventEmitter()
const userCreatedSymbol = Symbol('userCreated')
const userDeletedSymbol = Symbol('userDeleted')
emitter.on(userCreatedSymbol, (user: any) => {
console.log('User created:', user)
})
emitter.on(userDeletedSymbol, (userId: number) => {
console.log('User deleted:', userId)
})
emitter.emit(userCreatedSymbol, { id: 1, name: 'Alice' })
emitter.emit(userDeletedSymbol, 1)
console.log(emitter.getSymbolEvents()) // [Symbol(userCreated), Symbol(userDeleted)]
缓存系统
typescript
import { isSymbol } from 'radash'
class SymbolCache {
private cache = new Map<symbol, any>()
set(key: symbol, value: any): void {
if (!isSymbol(key)) {
throw new Error('Cache key must be a Symbol')
}
this.cache.set(key, value)
}
get<T>(key: symbol): T | undefined {
if (!isSymbol(key)) {
return undefined
}
return this.cache.get(key)
}
has(key: symbol): boolean {
return isSymbol(key) && this.cache.has(key)
}
delete(key: symbol): boolean {
if (!isSymbol(key)) {
return false
}
return this.cache.delete(key)
}
clear(): void {
this.cache.clear()
}
getSymbolKeys(): symbol[] {
return Array.from(this.cache.keys()).filter(isSymbol)
}
}
const cache = new SymbolCache()
const dataSymbol = Symbol('data')
const configSymbol = Symbol('config')
cache.set(dataSymbol, { items: [1, 2, 3] })
cache.set(configSymbol, { theme: 'dark' })
console.log(cache.get(dataSymbol)) // { items: [1, 2, 3] }
console.log(cache.has(configSymbol)) // true
console.log(cache.getSymbolKeys()) // [Symbol(data), Symbol(config)]
性能测试
typescript
import { isSymbol } from 'radash'
function benchmarkIsSymbol() {
const testValues = [
Symbol('test1'),
Symbol('test2'),
Symbol.iterator,
Symbol.toStringTag,
'symbol',
123,
true,
null,
undefined,
{},
[],
() => {}
]
const iterations = 1000000
const start = performance.now()
for (let i = 0; i < iterations; i++) {
testValues.forEach(value => {
isSymbol(value)
})
}
const end = performance.now()
console.log(`Benchmark completed in ${end - start}ms`)
}
// benchmarkIsSymbol() // 运行性能测试
边界值测试
typescript
import { isSymbol } from 'radash'
// 测试边界值
const boundaryTests = [
// Symbol类型
Symbol(),
Symbol(''),
Symbol('test'),
Symbol.iterator,
Symbol.asyncIterator,
Symbol.toStringTag,
Symbol.toPrimitive,
Symbol.unscopables,
Symbol.species,
Symbol.split,
Symbol.match,
Symbol.replace,
Symbol.search,
Symbol.hasInstance,
Symbol.isConcatSpreadable,
// 非Symbol类型
'Symbol()',
'symbol',
'Symbol.iterator',
123,
true,
false,
null,
undefined,
{},
[],
() => {},
new String('Symbol'),
new Object()
]
boundaryTests.forEach(value => {
console.log(`${typeof value} ${String(value).slice(0, 20)}: ${isSymbol(value)}`)
})
注意事项
- Symbol检测: 准确检测真正的Symbol类型
- 类型守卫: 作为TypeScript类型守卫使用
- 性能: 检查速度很快,适合高频使用
- 边界值: 正确处理所有边界情况
- 内置Symbol: 正确处理所有内置Symbol
与其他方法的区别
isSymbol()
: 检查是否为Symbol类型typeof value === 'symbol'
: 原生JavaScript检查value instanceof Symbol
: 不适用于Symbol(Symbol是原始类型)Object.prototype.toString.call(value) === '[object Symbol]'
: 复杂但准确
实际应用场景
- 元数据管理: 使用Symbol作为元数据键
- 私有属性: 模拟私有类成员
- 迭代器: 实现自定义迭代器
- 配置管理: 使用Symbol作为配置键
- 事件系统: 使用Symbol作为事件标识符
- 缓存系统: 使用Symbol作为缓存键