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作為緩存鍵