Skip to content

someAsync Method

The someAsync() method tests whether at least one element in the collection passes the provided async testing function. Returns a Promise that resolves to a boolean value.

Basic Syntax

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

Examples

Basic Usage

typescript
import { collect } from 'ts-collect'

// Simple async check
const numbers = collect([1, 2, 3, 4])
const hasEven = await numbers.someAsync(async (num) => {
  await new Promise(resolve => setTimeout(resolve, 100))
  return num % 2 === 0
})
console.log(hasEven)  // true

// External service check
const productIds = collect(['prod1', 'prod2', 'prod3'])
const hasAvailable = await productIds.someAsync(async (id) => {
  const response = await fetch(`/api/products/${id}/available`)
  const { inStock } = await response.json()
  return inStock
})

Working with Objects

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

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

// Check if any product is on sale
const hasDiscounts = await products.someAsync(async (product) => {
  const response = await fetch(`/api/prices/${product.sku}/discount`)
  const { hasDiscount } = await response.json()
  return hasDiscount
})

Real-world Examples

Product Availability Checker

typescript
interface InventoryItem {
  sku: string
  warehouse: string[]
  minQuantity: number
}

class AvailabilityChecker {
  constructor(private inventoryApi: string) {}

  async hasAvailableStock(items: Collection<InventoryItem>): Promise<{
    available: boolean
    availableSku?: string
    warehouse?: string
  }> {
    let foundSku: string | undefined
    let foundWarehouse: string | undefined

    const hasStock = await items.someAsync(async (item) => {
      // Check each warehouse for the item
      for (const warehouse of item.warehouse) {
        const hasStock = await this.checkWarehouseStock(item.sku, warehouse, item.minQuantity)
        if (hasStock) {
          foundSku = item.sku
          foundWarehouse = warehouse
          return true
        }
      }
      return false
    })

    return {
      available: hasStock,
      availableSku: foundSku,
      warehouse: foundWarehouse
    }
  }

  private async checkWarehouseStock(
    sku: string,
    warehouse: string,
    minQuantity: number
  ): Promise<boolean> {
    const response = await fetch(
      `${this.inventoryApi}/stock/${warehouse}/${sku}`
    )
    const { quantity } = await response.json()
    return quantity >= minQuantity
  }
}

Payment Method Validator

typescript
interface PaymentMethod {
  type: string
  customerId: string
  token: string
}

class PaymentValidator {
  constructor(private paymentApi: string) {}

  async hasValidPaymentMethod(
    methods: Collection<PaymentMethod>,
    amount: number
  ): Promise<{
    valid: boolean
    validMethod?: PaymentMethod
    error?: string
  }> {
    try {
      let validMethod: PaymentMethod | undefined

      const isValid = await methods.someAsync(async (method) => {
        const [tokenValid, fundsSufficient] = await Promise.all([
          this.validateToken(method),
          this.checkFunds(method, amount)
        ])

        if (tokenValid && fundsSufficient) {
          validMethod = method
          return true
        }
        return false
      })

      return {
        valid: isValid,
        validMethod: validMethod
      }
    } catch (error) {
      return {
        valid: false,
        error: error instanceof Error ? error.message : 'Unknown error'
      }
    }
  }

  private async validateToken(method: PaymentMethod): Promise<boolean> {
    const response = await fetch(`${this.paymentApi}/validate-token`, {
      method: 'POST',
      body: JSON.stringify({
        type: method.type,
        token: method.token
      })
    })
    return response.json()
  }

  private async checkFunds(method: PaymentMethod, amount: number): Promise<boolean> {
    const response = await fetch(`${this.paymentApi}/check-funds`, {
      method: 'POST',
      body: JSON.stringify({
        type: method.type,
        customerId: method.customerId,
        amount
      })
    })
    return response.json()
  }
}

Advanced Usage

Promotion Eligibility Checker

typescript
interface Promotion {
  code: string
  conditions: {
    minimumSpend?: number
    requiredItems?: string[]
    customerGroups?: string[]
  }
}

class PromotionChecker {
  constructor(
    private promotionApi: string,
    private customerApi: string
  ) {}

  async hasEligiblePromotion(
    promotions: Collection<Promotion>,
    cartTotal: number,
    customerId: string
  ): Promise<{
    eligible: boolean
    promotion?: Promotion
    reason?: string
  }> {
    let eligiblePromotion: Promotion | undefined
    let failureReason: string | undefined

    const isEligible = await promotions.someAsync(async (promotion) => {
      try {
        const [spendOk, itemsOk, groupOk] = await Promise.all([
          this.checkMinimumSpend(promotion, cartTotal),
          this.checkRequiredItems(promotion),
          this.checkCustomerGroup(promotion, customerId)
        ])

        if (!spendOk) {
          failureReason = 'Minimum spend not met'
          return false
        }

        if (!itemsOk) {
          failureReason = 'Required items not in cart'
          return false
        }

        if (!groupOk) {
          failureReason = 'Customer not in eligible group'
          return false
        }

        eligiblePromotion = promotion
        return true
      } catch (error) {
        failureReason = 'Error checking eligibility'
        return false
      }
    })

    return {
      eligible: isEligible,
      promotion: eligiblePromotion,
      reason: isEligible ? undefined : failureReason
    }
  }

  private async checkMinimumSpend(
    promotion: Promotion,
    cartTotal: number
  ): Promise<boolean> {
    if (!promotion.conditions.minimumSpend) return true
    return cartTotal >= promotion.conditions.minimumSpend
  }

  private async checkRequiredItems(promotion: Promotion): Promise<boolean> {
    if (!promotion.conditions.requiredItems?.length) return true

    const response = await fetch(`${this.promotionApi}/check-items`, {
      method: 'POST',
      body: JSON.stringify(promotion.conditions.requiredItems)
    })
    return response.json()
  }

  private async checkCustomerGroup(
    promotion: Promotion,
    customerId: string
  ): Promise<boolean> {
    if (!promotion.conditions.customerGroups?.length) return true

    const response = await fetch(`${this.customerApi}/check-groups`, {
      method: 'POST',
      body: JSON.stringify({
        customerId,
        groups: promotion.conditions.customerGroups
      })
    })
    return response.json()
  }
}

Type Safety

typescript
interface CheckableItem {
  id: string
  status: string
  flags: string[]
}

const items = collect<CheckableItem>([
  { id: '1', status: 'active', flags: ['new'] },
  { id: '2', status: 'inactive', flags: ['special'] }
])

// Type-safe async checking
const hasSpecial = await items.someAsync(async (item): Promise<boolean> => {
  const response = await fetch(`/api/check-flags/${item.id}`)
  return response.json()
})

// TypeScript enforces return type Promise<boolean>
const result: boolean = await hasSpecial

Return Value

  • Returns a Promise that resolves to a boolean
  • Returns true if any item passes the test
  • Returns false if all items fail
  • Returns false for empty collections
  • Executes tests in parallel
  • Short-circuits on first true

Common Use Cases

1. Availability Checks

  • Stock availability
  • Service availability
  • Delivery options
  • Time slots
  • Resource allocation

2. Payment Validation

  • Payment methods
  • Fund availability
  • Credit checks
  • Token validation
  • Account status

3. Promotion Checks

  • Eligibility validation
  • Code validation
  • Condition checks
  • Time restrictions
  • Group eligibility

4. Product Validation

  • Stock checks
  • Price validation
  • Feature availability
  • Market access
  • Restriction checks

5. User Validation

  • Permission checks
  • Group membership
  • Feature access
  • License validation
  • Status checks

6. Shipping Options

  • Service availability
  • Route validation
  • Rate checks
  • Time slots
  • Delivery options

7. Feature Access

  • Permission checks
  • License validation
  • Feature flags
  • Access rights
  • Subscription status

8. Service Checks

  • API availability
  • Service status
  • Resource access
  • Connection checks
  • Health validation

9. Business Rules

  • Condition checks
  • Policy validation
  • Rule evaluation
  • Constraint checks
  • Eligibility validation

10. Integration Status

  • Service checks
  • Connection status
  • API availability
  • Resource access
  • Health checks

Released under the MIT License.