Unfold Method
The unfold()
method generates a collection by repeatedly applying a function that produces both a value and the next state. It continues until the function returns null, making it ideal for generating sequences or expanding state-based data.
Basic Syntax
typescript
unfold<U>(fn: (seed: U) => [T, U] | null, initial: U): CollectionOperations<T>
Examples
Basic Usage
typescript
import { collect } from 'ts-collect'
// Generate Fibonacci sequence up to 100
const fibonacci = collect([0]).unfold((prev) => {
const next = prev + prev
return next > 100 ? null : [next, next]
}, 1)
console.log(fibonacci.all())
// [1, 2, 4, 8, 16, 32, 64]
Working with Complex States
typescript
interface PricePoint {
day: number
price: number
}
// Generate daily prices with 5% random variation
const priceGenerator = collect([]).unfold((state) => {
if (state.day > 7) return null // One week of prices
const variation = (Math.random() - 0.5) * 0.05
const newPrice = state.price * (1 + variation)
return [{
day: state.day,
price: newPrice
}, {
day: state.day + 1,
price: newPrice
}]
}, { day: 1, price: 100 })
Real-world Example: E-commerce Inventory Projection
typescript
interface InventoryState {
date: Date
stock: number
reorderPoint: number
onOrder: number
dailyDemand: number
}
interface InventorySnapshot {
date: Date
currentStock: number
expectedDeliveries: number
projectedDemand: number
needsReorder: boolean
}
class InventoryProjector {
projectInventory(
initialState: InventoryState,
daysToProject: number
): Collection<InventorySnapshot> {
return collect([]).unfold((state) => {
// Stop if we've projected enough days
const daysDiff = Math.floor(
(state.date.getTime() - initialState.date.getTime()) / (1000 * 60 * 60 * 24)
)
if (daysDiff >= daysToProject) return null
// Calculate next day's state
const nextDate = new Date(state.date)
nextDate.setDate(nextDate.getDate() + 1)
// Simulate stock changes
const expectedDemand = state.dailyDemand * (1 + (Math.random() - 0.5) * 0.2)
const deliveries = state.onOrder > 0 ? Math.min(state.onOrder, 100) : 0
const newStock = state.stock - expectedDemand + deliveries
// Create snapshot
const snapshot: InventorySnapshot = {
date: state.date,
currentStock: state.stock,
expectedDeliveries: state.onOrder,
projectedDemand: expectedDemand,
needsReorder: newStock < state.reorderPoint
}
// Prepare next state
const nextState: InventoryState = {
date: nextDate,
stock: Math.max(0, newStock),
reorderPoint: state.reorderPoint,
onOrder: Math.max(0, state.onOrder - deliveries),
dailyDemand: state.dailyDemand
}
return [snapshot, nextState]
}, initialState)
}
}
// Usage
const projector = new InventoryProjector()
const projection = projector.projectInventory({
date: new Date(),
stock: 1000,
reorderPoint: 200,
onOrder: 0,
dailyDemand: 50
}, 30) // Project 30 days
Type Safety
typescript
interface State {
count: number
value: string
}
// Type-safe unfolding
const sequence = collect([]).unfold((state: State) => {
if (state.count >= 3) return null
return [{
iteration: state.count,
data: state.value
}, {
count: state.count + 1,
value: state.value + '!'
}]
}, { count: 0, value: 'Hello' })
// TypeScript enforces return type structure
type SequenceItem = {
iteration: number
data: string
}
Return Value
- Returns a Collection of generated values
- Continues until function returns null
- Each iteration produces value and next state
- Maintains type safety through generics
- Preserves collection chain methods
- Empty collection if initial function returns null
Common Use Cases
1. Sequence Generation
- Numeric sequences
- Date ranges
- ID generation
- Pattern creation
- Series expansion
2. State Projection
- Inventory forecasting
- Growth modeling
- Balance projection
- Trend prediction
- Usage simulation
3. Data Generation
- Test data creation
- Sample generation
- Mock data sets
- Pattern simulation
- Scenario modeling
4. Time Series
- Date progressions
- Event sequences
- Schedule generation
- Timeline creation
- Period calculations
5. Resource Planning
- Capacity planning
- Resource allocation
- Demand forecasting
- Supply projection
- Usage patterns