Skip to content

Sole Method

The sole() method returns the first element in the collection that matches the given condition, but only if exactly one element matches. If no elements match or more than one element matches, it returns undefined.

Basic Syntax

typescript
// Get the sole item matching a callback
collect(items).sole((item: T) => boolean)

// Get the sole item matching a key-value pair
collect(items).sole(key: string, value: any)

Examples

Basic Usage

typescript
import { collect } from 'ts-collect'

// With callback
const numbers = collect([1, 2, 3, 4])
console.log(numbers.sole(n => n > 3)) // 4

// Multiple matches returns undefined
console.log(numbers.sole(n => n > 2)) // undefined

// No matches returns undefined
console.log(numbers.sole(n => n > 10)) // undefined

// With key-value pair
const items = collect([
  { id: 1, type: 'A' },
  { id: 2, type: 'B' },
  { id: 3, type: 'A' }
])

console.log(items.sole('type', 'B')) // { id: 2, type: 'B' }
console.log(items.sole('type', 'A')) // undefined (multiple matches)

Working with Objects

typescript
interface User {
  id: number
  name: string
  role: string
  active: boolean
}

const users = collect<User>([
  { id: 1, name: 'John', role: 'admin', active: true },
  { id: 2, name: 'Jane', role: 'user', active: true },
  { id: 3, name: 'Bob', role: 'moderator', active: true }
])

// Find sole admin
const admin = users.sole(user => user.role === 'admin')
console.log(admin) // { id: 1, name: 'John', role: 'admin', active: true }

// Find sole moderator
const moderator = users.sole('role', 'moderator')
console.log(moderator) // { id: 3, name: 'Bob', role: 'moderator', active: true }

Real-world Examples

Configuration Validator

typescript
interface ConfigEntry {
  key: string
  value: string
  environment: string
  isDefault: boolean
}

class ConfigValidator {
  private configs: Collection<ConfigEntry>

  constructor(configs: ConfigEntry[]) {
    this.configs = collect(configs)
  }

  getDefaultConfig(key: string): ConfigEntry | undefined {
    return this.configs.sole(config =>
      config.key === key && config.isDefault
    )
  }

  validateUniqueDefaults(): boolean {
    for (const key of new Set(this.configs.pluck('key'))) {
      const defaultConfig = this.getDefaultConfig(key)
      if (!defaultConfig) {
        return false
      }
    }
    return true
  }
}

License Manager

typescript
interface License {
  id: string
  type: string
  status: 'active' | 'expired' | 'revoked'
  userId: string
  features: string[]
}

class LicenseManager {
  private licenses: Collection<License>

  constructor(licenses: License[]) {
    this.licenses = collect(licenses)
  }

  getActiveLicense(userId: string): License | undefined {
    return this.licenses.sole(license =>
      license.userId === userId
      && license.status === 'active'
    )
  }

  validateSingleActiveLicense(userId: string): boolean {
    return this.getActiveLicense(userId) !== undefined
  }
}

Advanced Usage

System Health Monitor

typescript
interface SystemStatus {
  componentId: string
  status: 'healthy' | 'degraded' | 'failed'
  lastCheck: Date
  metrics: {
    cpu: number
    memory: number
    disk: number
  }
}

class SystemMonitor {
  private statuses: Collection<SystemStatus>

  constructor(statuses: SystemStatus[]) {
    this.statuses = collect(statuses)
  }

  findFailedComponent(): SystemStatus | undefined {
    return this.statuses.sole(status => status.status === 'failed')
  }

  hasUniqueDegradation(): boolean {
    return this.statuses.sole(
      status => status.status === 'degraded'
    ) !== undefined
  }

  findHighCpuComponent(): SystemStatus | undefined {
    return this.statuses.sole(
      status => status.metrics.cpu > 90
    )
  }
}

Database Connection Manager

typescript
interface DatabaseConnection {
  id: string
  type: 'primary' | 'replica' | 'backup'
  status: 'connected' | 'disconnected'
  priority: number
}

class ConnectionManager {
  private connections: Collection<DatabaseConnection>

  constructor(connections: DatabaseConnection[]) {
    this.connections = collect(connections)
  }

  getPrimaryConnection(): DatabaseConnection | undefined {
    return this.connections.sole(conn =>
      conn.type === 'primary'
      && conn.status === 'connected'
    )
  }

  validateSinglePrimary(): boolean {
    return this.connections.sole('type', 'primary') !== undefined
  }
}

Type Safety

typescript
interface TypedItem {
  id: number
  value: string
  status: 'active' | 'inactive'
  metadata?: Record<string, any>
}

const items = collect<TypedItem>([
  { id: 1, value: 'one', status: 'active' },
  { id: 2, value: 'two', status: 'inactive' },
  { id: 3, value: 'three', status: 'active' }
])

// Type-safe callback
const item = items.sole((item: TypedItem) => {
  return item.status === 'inactive' // TypeScript validates status values
})

// Type-safe key-value matching
const result = items.sole('status', 'inactive')

Return Value

  • Returns the single matching element if exactly one element matches
  • Returns undefined if:
    • No elements match the condition
    • Multiple elements match the condition
  • Original collection remains unchanged
  • Maintains type safety with TypeScript
  • Can be used with both callback functions and key-value pairs

Released under the MIT License.