Skip to content

FlatMap Method

The flatMap() method maps each element in the collection using a callback function, then flattens the result into a single collection. It's particularly useful when your mapping operation returns arrays that you want to combine.

Basic Syntax

typescript
collect(items).flatMap<U>((item: T, index: number) => U[]): Collection<U>

Examples

Basic Usage

typescript
import { collect } from 'ts-collect'

// Expand numbers into ranges
const numbers = collect([1, 2, 3])
const expanded = numbers.flatMap(n => [n, n + 0.5])
console.log(expanded.all()) // [1, 1.5, 2, 2.5, 3, 3.5]

// Split strings and combine
const words = collect(['hello world', 'typescript rocks'])
const allWords = words.flatMap(str => str.split(' '))
console.log(allWords.all()) // ['hello', 'world', 'typescript', 'rocks']

Working with Objects

typescript
interface User {
  id: number
  name: string
  roles: string[]
}

interface UserRole {
  userId: number
  userName: string
  role: string
}

const users = collect<User>([
  { id: 1, name: 'John', roles: ['admin', 'user'] },
  { id: 2, name: 'Jane', roles: ['user'] }
])

// Expand users into role-specific records
const userRoles = users.flatMap<UserRole>(user =>
  user.roles.map(role => ({
    userId: user.id,
    userName: user.name,
    role
  }))
)

console.log(userRoles.all())
// [
//   { userId: 1, userName: 'John', role: 'admin' },
//   { userId: 1, userName: 'John', role: 'user' },
//   { userId: 2, userName: 'Jane', role: 'user' }
// ]

Real-world Examples

Permission Expander

typescript
interface Permission {
  resource: string
  actions: string[]
  conditions?: string[]
}

interface ExpandedPermission {
  resource: string
  action: string
  condition?: string
}

class PermissionExpander {
  expandPermissions(permissions: Permission[]): Collection<ExpandedPermission> {
    return collect(permissions).flatMap((permission) => {
      const basePermissions = permission.actions.map(action => ({
        resource: permission.resource,
        action
      }))

      if (!permission.conditions) {
        return basePermissions
      }

      return basePermissions.flatMap(base =>
        permission.conditions!.map(condition => ({
          ...base,
          condition
        }))
      )
    })
  }
}

Event Schedule Generator

typescript
interface EventTemplate {
  name: string
  weekdays: number[]
  timeSlots: string[]
}

interface ScheduledEvent {
  name: string
  datetime: Date
  duration: number
}

class EventScheduler {
  generateEvents(
    template: EventTemplate,
    startDate: Date,
    weeks: number
  ): Collection<ScheduledEvent> {
    const dates = this.generateDates(startDate, weeks)

    return collect(dates).flatMap(date =>
      template.weekdays.includes(date.getDay())
        ? template.timeSlots.map(timeSlot => ({
            name: template.name,
            datetime: this.combineDateTime(date, timeSlot),
            duration: 60 // minutes
          }))
        : []
    )
  }

  private generateDates(start: Date, weeks: number): Date[] {
    // Generate array of dates for the specified weeks
    return []
  }

  private combineDateTime(date: Date, timeSlot: string): Date {
    // Combine date and time slot into DateTime
    return new Date()
  }
}

Advanced Usage

Query Parameter Builder

typescript
interface QueryFilter {
  field: string
  operators: string[]
  values: any[]
}

interface QueryParameter {
  key: string
  value: string
  operator: string
}

class QueryBuilder {
  buildParameters(filters: QueryFilter[]): Collection<QueryParameter> {
    return collect(filters).flatMap(filter =>
      filter.operators.flatMap(operator =>
        filter.values.map(value => ({
          key: filter.field,
          value: String(value),
          operator
        }))
      )
    )
  }

  generateQueryString(filters: QueryFilter[]): string {
    return this.buildParameters(filters)
      .map(param =>
        `${param.key}${param.operator}${encodeURIComponent(param.value)}`
      )
      .join('&')
  }
}

Tree Traversal

typescript
interface TreeNode<T> {
  value: T
  children: TreeNode<T>[]
}

class TreeTraverser<T> {
  flattenTree(root: TreeNode<T>): Collection<T> {
    return collect([root]).flatMap(node => [
      node.value,
      ...this.flattenChildren(node.children)
    ])
  }

  private flattenChildren(nodes: TreeNode<T>[]): T[] {
    return collect(nodes).flatMap(node => [
      node.value,
      ...this.flattenChildren(node.children)
    ]).all()
  }

  getLeafNodes(root: TreeNode<T>): Collection<T> {
    return collect([root]).flatMap(node =>
      node.children.length === 0
        ? [node.value]
        : this.getLeafNodes(node.children).all()
    )
  }
}

Type Safety

typescript
interface SourceType {
  id: number
  values: string[]
}

interface TargetType {
  sourceId: number
  value: string
  index: number
}

const items = collect<SourceType>([
  { id: 1, values: ['a', 'b'] },
  { id: 2, values: ['c'] }
])

// Type-safe transformation with index
const result = items.flatMap<TargetType>((item, sourceIndex) =>
  item.values.map((value, valueIndex) => ({
    sourceId: item.id,
    value,
    index: sourceIndex * 100 + valueIndex
  }))
)

Return Value

  • Returns a new Collection instance containing all flattened and mapped items
  • Transforms each item into an array of new items
  • Concatenates all resulting arrays into a single flat collection
  • Original collection remains unchanged
  • Maintains type safety with TypeScript through generics
  • Can be chained with other collection methods
  • Index parameter in callback is optional

Common Use Cases

1. Data Expansion

  • Expanding nested arrays
  • Converting one-to-many relationships
  • Generating combinations
  • Creating data permutations

2. Permission Processing

  • Expanding role permissions
  • Generating access rules
  • Creating security policies
  • Processing authorization rules

3. Event Generation

  • Creating recurring events
  • Generating schedules
  • Expanding time slots
  • Processing calendar data

4. Query Building

  • Generating query parameters
  • Building search criteria
  • Creating filter combinations
  • Expanding search terms

5. Data Transformation

  • Converting complex structures
  • Processing nested data
  • Flattening hierarchies
  • Normalizing data structures

6. Text Processing

  • Tokenizing text
  • Processing sentences
  • Extracting keywords
  • Generating variations

7. Tree Operations

  • Flattening tree structures
  • Processing hierarchical data
  • Extracting node information
  • Traversing graphs

8. Relationship Mapping

  • Processing many-to-many relationships
  • Expanding associations
  • Generating connection maps
  • Creating relationship matrices

9. Configuration Expansion

  • Processing configuration templates
  • Generating settings combinations
  • Expanding rule sets
  • Creating configuration variants

10. Dataset Generation

  • Creating test data
  • Generating sample sets
  • Producing data variations
  • Building training datasets

Released under the MIT License.