Skip to content

whereNotNull Method

The whereNotNull() method filters the collection to include only items where the specified key's value is not null or undefined. This is particularly useful for finding complete records and validating data presence.

Basic Syntax

typescript
collect(items).whereNotNull(key: keyof T): Collection<T>

Examples

Basic Usage

typescript
import { collect } from 'ts-collect'

// Simple not-null check
const items = collect([
  { id: 1, name: 'Widget', description: null },
  { id: 2, name: 'Gadget', description: 'A cool gadget' },
  { id: 3, name: 'Tool', description: null }
])

const withDescriptions = items.whereNotNull('description')
console.log(withDescriptions.all())
// [
//   { id: 2, name: 'Gadget', description: 'A cool gadget' }
// ]

Working with Objects

typescript
interface Product {
  id: number
  name: string
  price: number | null
  inStock: boolean | null
  lastSold: Date | null
}

const products = collect<Product>([
  { id: 1, name: 'Widget', price: 99.99, inStock: true, lastSold: new Date() },
  { id: 2, name: 'Gadget', price: null, inStock: true, lastSold: null },
  { id: 3, name: 'Tool', price: 49.99, inStock: null, lastSold: new Date() }
])

// Find products with prices
const pricedProducts = products.whereNotNull('price')

// Find products with known stock status
const stockKnown = products.whereNotNull('inStock')

// Find products with sales history
const withSales = products.whereNotNull('lastSold')

Real-world Examples

Product Listing Manager

typescript
interface ListingData {
  sku: string
  name: string
  description: string | null
  price: number | null
  images: string[] | null
  specifications: Record<string, string> | null
}

class ListingManager {
  constructor(private listings: Collection<ListingData>) {}

  getPublishableListings(): Collection<ListingData> {
    return this.listings
      .whereNotNull('description')
      .whereNotNull('price')
      .whereNotNull('images')
      .whereNotNull('specifications')
  }

  getListingStatus(): {
    total: number,
    publishable: number,
    requiresWork: Collection<ListingData>
  } {
    const publishable = this.getPublishableListings()

    return {
      total: this.listings.count(),
      publishable: publishable.count(),
      requiresWork: this.listings
        .filter(listing => !publishable.pluck('sku').contains(listing.sku))
    }
  }

  getCompletionReport(): Record<string, number> {
    return {
      description: this.listings.whereNotNull('description').count(),
      price: this.listings.whereNotNull('price').count(),
      images: this.listings.whereNotNull('images').count(),
      specifications: this.listings.whereNotNull('specifications').count()
    }
  }
}

Order Tracking System

typescript
interface OrderStatus {
  orderId: string
  processedAt: Date | null
  shippedAt: Date | null
  deliveredAt: Date | null
  trackingNumber: string | null
  estimatedDelivery: Date | null
}

class OrderTracker {
  constructor(private orders: Collection<OrderStatus>) {}

  getActiveShipments(): Collection<OrderStatus> {
    return this.orders
      .whereNotNull('shippedAt')
      .whereNotNull('trackingNumber')
      .whereNull('deliveredAt')
  }

  getTrackableOrders(): Collection<OrderStatus> {
    return this.orders
      .whereNotNull('trackingNumber')
      .whereNotNull('estimatedDelivery')
  }

  getShipmentProgress(): Record<string, number> {
    const total = this.orders.count()
    return {
      processed: this.orders.whereNotNull('processedAt').count() / total * 100,
      shipped: this.orders.whereNotNull('shippedAt').count() / total * 100,
      delivered: this.orders.whereNotNull('deliveredAt').count() / total * 100
    }
  }
}

Advanced Usage

Customer Analysis System

typescript
interface CustomerData {
  id: string
  email: string
  phoneNumber: string | null
  preferences: string[] | null
  lastPurchase: Date | null
  segment: string | null
}

class CustomerAnalyzer {
  constructor(private customers: Collection<CustomerData>) {}

  getMarketableCustomers(): {
    email: Collection<CustomerData>,
    phone: Collection<CustomerData>,
    both: Collection<CustomerData>
  } {
    const withEmail = this.customers.whereNotNull('email')
    const withPhone = this.customers.whereNotNull('phoneNumber')

    return {
      email: withEmail,
      phone: withPhone,
      both: withEmail.intersect(withPhone)
    }
  }

  getSegmentedCustomers(): Collection<CustomerData> {
    return this.customers
      .whereNotNull('segment')
      .whereNotNull('preferences')
  }

  getActiveCustomers(): Collection<CustomerData> {
    return this.customers
      .whereNotNull('lastPurchase')
      .filter(customer => {
        const lastPurchase = new Date(customer.lastPurchase!)
        const thirtyDaysAgo = new Date()
        thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30)
        return lastPurchase >= thirtyDaysAgo
      })
  }
}

Type Safety

typescript
interface TypedProduct {
  id: number
  name: string
  description: string | null
  price: number | null
}

const products = collect<TypedProduct>([
  { id: 1, name: 'A', description: null, price: 100 },
  { id: 2, name: 'B', description: 'Test', price: null }
])

// Type-safe not-null checks
const withDescription = products.whereNotNull('description')
const withPrice = products.whereNotNull('price')

// TypeScript enforces valid keys and nullable types
// products.whereNotNull('name')  // ✗ TypeScript error for non-nullable field
// products.whereNotNull('invalid')  // ✗ TypeScript error for invalid key

Return Value

  • Returns a new Collection containing only items where the specified key is not null
  • Original collection remains unchanged
  • Maintains type safety with TypeScript
  • Can be chained with other collection methods
  • Excludes both null and undefined values
  • Empty collection if no matches found

Common Use Cases

1. Product Management

  • Complete listings
  • Valid products
  • Active items
  • Publishable content
  • Available items

2. Order Processing

  • Trackable shipments
  • Valid orders
  • Complete information
  • Active deliveries
  • Processable orders

3. Customer Management

  • Valid contacts
  • Complete profiles
  • Active customers
  • Marketable users
  • Segmented customers

4. Inventory Control

  • Available stock
  • Valid items
  • Active products
  • Trackable inventory
  • Complete records

5. Marketing Analysis

  • Valid segments
  • Complete campaigns
  • Active promotions
  • Trackable metrics
  • Analyzable data

6. Data Validation

  • Complete records
  • Valid entries
  • Active status
  • Required fields
  • Quality checks

7. Reporting

  • Valid metrics
  • Complete data
  • Active periods
  • Analyzable records
  • Valid comparisons

8. User Management

  • Active users
  • Valid accounts
  • Complete profiles
  • Verified users
  • Contactable customers

9. Content Management

  • Published content
  • Valid entries
  • Complete articles
  • Active listings
  • Viewable items

10. Analytics

  • Valid metrics
  • Complete datasets
  • Active tracking
  • Analyzable periods
  • Reportable data

Released under the MIT License.