Skip to content

FirstOrFail Method

The firstOrFail() method returns the first element in the collection that passes a given truth test. If no element is found, it throws a CollectionException. This is particularly useful when you expect an element to exist and want to handle its absence as an error condition.

Basic Syntax

typescript
// Simple usage
collect(items).firstOrFail()

// With callback
const callback: (item: T) => boolean // optional
collect(items).firstOrFail(callback)

// With default value
const defaultValue: any // optional
collect(items).firstOrFail(defaultValue)

Examples

Basic Usage

typescript
import { collect } from 'ts-collect'

// With data present
const numbers = collect([1, 2, 3, 4, 5])
console.log(numbers.firstOrFail()) // 1

// With empty collection
try {
  const empty = collect([])
  empty.firstOrFail()
}
catch (error) {
  console.error('Error:', error.message) // "Item not found."
}

Using with Callback

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

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

try {
  const activeUser = users.firstOrFail(user => user.active)
  console.log(activeUser) // { id: 2, name: 'Jane', active: true }
}
catch (error) {
  console.error('No active user found')
}

Real-world Examples

Database Record Retrieval

typescript
interface DatabaseRecord {
  id: number
  status: 'active' | 'archived' | 'deleted'
  data: object
}

function findActiveRecord(records: DatabaseRecord[]) {
  try {
    return collect(records).firstOrFail(record => record.status === 'active')
  }
  catch (error) {
    throw new Error('No active record found in the database')
  }
}

// Usage
const records: DatabaseRecord[] = [
  { id: 1, status: 'deleted', data: {} },
  { id: 2, status: 'active', data: { foo: 'bar' } },
  { id: 3, status: 'archived', data: {} }
]

const activeRecord = findActiveRecord(records)
console.log(activeRecord) // { id: 2, status: 'active', data: { foo: 'bar' } }

User Authentication

typescript
interface UserSession {
  id: string
  userId: number
  token: string
  expiresAt: Date
  active: boolean
}

function getValidSession(sessions: UserSession[]) {
  const now = new Date()

  try {
    return collect(sessions).firstOrFail(session =>
      session.active && new Date(session.expiresAt) > now
    )
  }
  catch (error) {
    throw new Error('No valid session found')
  }
}

// Usage
const sessions: UserSession[] = [
  {
    id: 's1',
    userId: 1,
    token: 'token1',
    expiresAt: new Date('2024-12-31'),
    active: true
  },
  {
    id: 's2',
    userId: 1,
    token: 'token2',
    expiresAt: new Date('2023-12-31'),
    active: false
  }
]

try {
  const validSession = getValidSession(sessions)
  console.log('Valid session found:', validSession)
}
catch (error) {
  console.error('Session validation failed:', error.message)
}

Error Handling Examples

Custom Error Messages

typescript
interface Product {
  id: number
  name: string
  stock: number
  price: number
}

function findAvailableProduct(products: Product[], minStock: number = 1) {
  try {
    return collect(products).firstOrFail(product => product.stock >= minStock)
  }
  catch (error) {
    throw new Error(`No product found with minimum stock of ${minStock}`)
  }
}

// Usage
const products: Product[] = [
  { id: 1, name: 'Laptop', stock: 0, price: 999 },
  { id: 2, name: 'Mouse', stock: 5, price: 29.99 }
]

try {
  const product = findAvailableProduct(products, 10)
}
catch (error) {
  console.error(error.message) // "No product found with minimum stock of 10"
}

Advanced Usage

Chaining with Other Methods

typescript
interface Task {
  id: number
  priority: number
  status: 'pending' | 'in_progress' | 'completed'
  assignee?: string
}

const tasks = collect<Task>([
  { id: 1, priority: 1, status: 'completed' },
  { id: 2, priority: 2, status: 'pending' },
  { id: 3, priority: 3, status: 'in_progress' }
])

try {
  const highPriorityPending = tasks
    .filter(task => task.status === 'pending')
    .sortByDesc('priority')
    .firstOrFail()

  console.log(highPriorityPending)
  // { id: 2, priority: 2, status: 'pending' }
}
catch (error) {
  console.error('No pending tasks found')
}

Type Safety

typescript
interface TypedItem {
  id: number
  value: string
  optional?: number
}

const items = collect<TypedItem>([
  { id: 1, value: 'first' },
  { id: 2, value: 'second', optional: 42 }
])

// Type-safe callback usage
try {
  const item = items.firstOrFail((item: TypedItem) => {
    return item.optional !== undefined // TypeScript knows about optional
  })
  console.log(item.optional) // TypeScript knows this is safe
}
catch (error) {
  console.error('No item with optional value found')
}

Return Value

  • Returns the first element that passes the truth test
  • Throws a CollectionException if no element is found
  • If a default value is provided and no element is found, returns the default value instead of throwing

Released under the MIT License.