Skip to content

filterAsync Method

The filterAsync() method filters items in the collection using an asynchronous callback function. It returns a Promise that resolves to a new collection containing only the items that pass the async test.

Basic Syntax

typescript
collect(items).filterAsync(callback: AsyncCallback<T, boolean>): Promise<Collection<T>>

Examples

Basic Usage

typescript
import { collect } from 'ts-collect'

// Simple async filtering
const items = collect([1, 2, 3, 4, 5])
const evenNumbers = await items.filterAsync(async (num) => {
  await new Promise(resolve => setTimeout(resolve, 100))
  return num % 2 === 0
})
console.log(evenNumbers.all())  // [2, 4]

// With external validation
const userIds = collect(['user1', 'user2', 'user3'])
const activeUsers = await userIds.filterAsync(async (userId) => {
  const response = await fetch(`/api/users/${userId}/status`)
  const { active } = await response.json()
  return active
})

Working with Objects

typescript
interface Product {
  id: number
  sku: string
  price: number
}

const products = collect<Product>([
  { id: 1, sku: 'WIDGET-1', price: 100 },
  { id: 2, sku: 'GADGET-1', price: 200 }
])

// Check stock availability
const inStockProducts = await products.filterAsync(async (product) => {
  const response = await fetch(`/api/inventory/${product.sku}/available`)
  const { inStock } = await response.json()
  return inStock
})

Real-world Examples

Product Availability Checker

typescript
interface InventoryItem {
  sku: string
  name: string
  warehouse: string
  quantity: number
}

class AvailabilityChecker {
  constructor(
    private inventoryApi: string,
    private minimumQuantity: number = 1
  ) {}

  async getAvailableProducts(items: Collection<InventoryItem>): Promise<Collection<InventoryItem>> {
    return items.filterAsync(async (item) => {
      try {
        const [stockResponse, reservationsResponse] = await Promise.all([
          this.checkStock(item.sku),
          this.checkReservations(item.sku)
        ])

        const availableQuantity = stockResponse.quantity - reservationsResponse.reserved
        return availableQuantity >= this.minimumQuantity
      } catch (error) {
        console.error(`Error checking availability for ${item.sku}:`, error)
        return false
      }
    })
  }

  private async checkStock(sku: string) {
    const response = await fetch(`${this.inventoryApi}/stock/${sku}`)
    return response.json()
  }

  private async checkReservations(sku: string) {
    const response = await fetch(`${this.inventoryApi}/reservations/${sku}`)
    return response.json()
  }
}

Order Validator

typescript
interface Order {
  id: string
  customerId: string
  items: Array<{
    productId: string
    quantity: number
  }>
  totalAmount: number
}

class OrderValidator {
  constructor(private maxConcurrentChecks: number = 5) {}

  async getValidOrders(orders: Collection<Order>): Promise<Collection<Order>> {
    let runningChecks = 0
    const queue: Array<() => void> = []

    return orders.filterAsync(async (order) => {
      // Wait if too many concurrent checks
      if (runningChecks >= this.maxConcurrentChecks) {
        await new Promise<void>(resolve => queue.push(resolve))
      }

      runningChecks++

      try {
        const [
          customerValid,
          itemsAvailable,
          paymentValid
        ] = await Promise.all([
          this.validateCustomer(order.customerId),
          this.validateItemsAvailability(order.items),
          this.validatePayment(order)
        ])

        return customerValid && itemsAvailable && paymentValid
      } finally {
        runningChecks--
        if (queue.length > 0) {
          const next = queue.shift()
          next?.()
        }
      }
    })
  }

  private async validateCustomer(customerId: string): Promise<boolean> {
    const response = await fetch(`/api/customers/${customerId}/validate`)
    return response.json()
  }

  private async validateItemsAvailability(items: Array<{ productId: string, quantity: number }>): Promise<boolean> {
    const checks = await Promise.all(
      items.map(async item => {
        const response = await fetch(`/api/products/${item.productId}/available/${item.quantity}`)
        return response.json()
      })
    )
    return checks.every(result => result.available)
  }

  private async validatePayment(order: Order): Promise<boolean> {
    const response = await fetch('/api/payments/validate', {
      method: 'POST',
      body: JSON.stringify(order)
    })
    return response.json()
  }
}

Advanced Usage

Content Moderator

typescript
interface Content {
  id: string
  title: string
  body: string
  authorId: string
  tags: string[]
}

class ContentModerator {
  constructor(
    private moderationApi: string,
    private profanityApi: string,
    private userApi: string
  ) {}

  async getAppropriateContent(content: Collection<Content>): Promise<Collection<Content>> {
    return content.filterAsync(async (item) => {
      const [
        moderationPassed,
        noProfanity,
        authorValid
      ] = await Promise.all([
        this.checkModeration(item),
        this.checkProfanity(item),
        this.checkAuthor(item.authorId)
      ])

      return moderationPassed && noProfanity && authorValid
    })
  }

  private async checkModeration(content: Content): Promise<boolean> {
    const response = await fetch(`${this.moderationApi}/check`, {
      method: 'POST',
      body: JSON.stringify({
        text: content.body,
        title: content.title,
        tags: content.tags
      })
    })
    return response.json()
  }

  private async checkProfanity(content: Content): Promise<boolean> {
    const response = await fetch(`${this.profanityApi}/validate`, {
      method: 'POST',
      body: JSON.stringify({
        text: `${content.title} ${content.body}`
      })
    })
    const { clean } = await response.json()
    return clean
  }

  private async checkAuthor(authorId: string): Promise<boolean> {
    const response = await fetch(`${this.userApi}/users/${authorId}/standing`)
    const { goodStanding } = await response.json()
    return goodStanding
  }
}

Type Safety

typescript
interface Product {
  id: number
  sku: string
  price: number
}

const products = collect<Product>([
  { id: 1, sku: 'ABC', price: 100 },
  { id: 2, sku: 'DEF', price: 200 }
])

// Type-safe async filtering
const filtered = await products.filterAsync(async (product): Promise<boolean> => {
  const response = await fetch(`/api/products/${product.sku}/validate`)
  return response.json()
})

// TypeScript enforces return type Promise<Collection<Product>>
const result: Collection<Product> = await filtered

Return Value

  • Returns a Promise that resolves to a new Collection
  • Original collection remains unchanged
  • Maintains type safety with TypeScript
  • Can be chained with other collection methods
  • Preserves item order for matching items
  • Empty collection if no items pass the test

Common Use Cases

1. Inventory Validation

  • Stock checking
  • Availability verification
  • Supplier validation
  • Location verification
  • Quantity confirmation

2. Order Processing

  • Payment validation
  • Stock verification
  • Customer checks
  • Shipping validation
  • Discount verification

3. Content Moderation

  • Text moderation
  • Image validation
  • Tag verification
  • Author validation
  • Category checks

4. User Validation

  • Permission checks
  • Status verification
  • Account validation
  • Access control
  • Role verification

5. Payment Processing

  • Fund verification
  • Account validation
  • Credit checks
  • Fraud detection
  • Balance confirmation

6. Data Validation

  • External validation
  • Format verification
  • Rule checking
  • Constraint validation
  • Dependency verification

7. Product Management

  • Availability checks
  • Price validation
  • Category verification
  • Supplier validation
  • Feature verification

8. Security Checks

  • Authorization checks
  • Access validation
  • Token verification
  • Rate limiting
  • Compliance validation

9. Integration Validation

  • API verification
  • Service checks
  • External validation
  • System integration
  • Connection verification

10. Business Rules

  • Policy validation
  • Rule enforcement
  • Constraint checking
  • Threshold validation
  • Limit verification

Released under the MIT License.