Skip to content

SkipUntil Method

The skipUntil() method skips items in the collection until the given callback returns true, and then returns the remaining items. It can also accept a value to compare against.

Basic Syntax

typescript
// With callback
collect(items).skipUntil((item: T) => boolean)

// With value
collect(items).skipUntil(value: any)

Examples

Basic Usage

typescript
import { collect } from 'ts-collect'

// Using a callback
const numbers = collect([1, 2, 3, 4, 5, 6])
console.log(numbers.skipUntil(num => num > 3).all())
// [4, 5, 6]

// Using a value
const letters = collect(['a', 'b', 'c', 'd', 'e'])
console.log(letters.skipUntil('c').all())
// ['c', 'd', 'e']

Working with Objects

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

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

// Skip until we find an incomplete task
const incompleteTasks = tasks.skipUntil(
  task => task.status !== 'completed'
)
console.log(incompleteTasks.all())
// [
//   { id: 2, status: 'pending', priority: 2 },
//   { id: 3, status: 'in_progress', priority: 3 },
//   { id: 4, status: 'pending', priority: 4 }
// ]

Real-world Examples

Log Analysis

typescript
interface LogEntry {
  timestamp: Date
  level: 'info' | 'warning' | 'error'
  message: string
  metadata?: Record<string, any>
}

class LogAnalyzer {
  private logs: Collection<LogEntry>

  constructor(logs: LogEntry[]) {
    this.logs = collect(logs)
  }

  getLogsFromFirstError(): LogEntry[] {
    return this.logs
      .skipUntil(log => log.level === 'error')
      .all()
  }

  getLogsFromDate(date: Date): LogEntry[] {
    return this.logs
      .skipUntil(log => log.timestamp >= date)
      .all()
  }
}

// Usage
const analyzer = new LogAnalyzer([
  {
    timestamp: new Date('2024-01-01'),
    level: 'info',
    message: 'System start'
  },
  {
    timestamp: new Date('2024-01-02'),
    level: 'error',
    message: 'System crash'
  },
  {
    timestamp: new Date('2024-01-03'),
    level: 'info',
    message: 'System recovery'
  }
])

Transaction Processing

typescript
interface Transaction {
  id: string
  date: Date
  amount: number
  status: 'pending' | 'processed' | 'failed'
  verification?: boolean
}

class TransactionProcessor {
  private transactions: Collection<Transaction>

  constructor(transactions: Transaction[]) {
    this.transactions = collect(transactions)
  }

  processFromFirstVerified() {
    return this.transactions
      .skipUntil(tx => tx.verification === true)
      .map(tx => this.processTransaction(tx))
      .all()
  }

  processFromDate(startDate: Date) {
    return this.transactions
      .skipUntil(tx => tx.date >= startDate)
      .map(tx => this.processTransaction(tx))
      .all()
  }

  private processTransaction(tx: Transaction): Transaction {
    // Processing logic...
    return {
      ...tx,
      status: 'processed'
    }
  }
}

Advanced Usage

Event Stream Processing

typescript
interface Event {
  id: string
  type: string
  timestamp: Date
  priority: number
  data: any
}

class EventStreamProcessor {
  private events: Collection<Event>
  private processingStartTime: Date

  constructor(events: Event[]) {
    this.events = collect(events)
    this.processingStartTime = new Date()
  }

  processFromPriority(minPriority: number) {
    return this.events
      .skipUntil(event => event.priority >= minPriority)
      .map(this.processEvent)
      .all()
  }

  processFromTimestamp(timestamp: Date) {
    return this.events
      .skipUntil(event => event.timestamp >= timestamp)
      .map(this.processEvent)
      .all()
  }

  private processEvent(event: Event) {
    // Event processing logic...
    return {
      ...event,
      processed: true,
      processedAt: new Date()
    }
  }
}

Data Stream Parser

typescript
interface DataPacket {
  sequence: number
  type: string
  content: string
  valid: boolean
}

class DataStreamParser {
  private packets: Collection<DataPacket>
  private readonly startSequence: number

  constructor(packets: DataPacket[], startSequence: number = 0) {
    this.packets = collect(packets)
    this.startSequence = startSequence
  }

  parseFromSequence() {
    return this.packets
      .skipUntil(packet => packet.sequence >= this.startSequence)
      .filter(packet => packet.valid)
      .map(this.parsePacket)
      .all()
  }

  parseFromValidPacket() {
    return this.packets
      .skipUntil(packet => packet.valid)
      .map(this.parsePacket)
      .all()
  }

  private parsePacket(packet: DataPacket) {
    // Parsing logic...
    return {
      ...packet,
      parsed: true,
      content: packet.content.toUpperCase()
    }
  }
}

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: 'inactive' },
  { id: 2, value: 'two', status: 'active' },
  { id: 3, value: 'three', status: 'active' }
])

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

// Using with value
const fromTwo = items.skipUntil({ id: 2, value: 'two', status: 'active' })

Return Value

  • Returns a new Collection instance containing items from the first match onwards
  • Returns empty collection if no items match the condition
  • Original collection remains unchanged
  • Maintains type safety with TypeScript
  • Can be chained with other collection methods

Released under the MIT License.