Skip to content

Complete Documentation โ€‹

Key Features โ€‹

  • ๐ŸŽฏ SQL-like Wildcards - Use % and _ for flexible pattern matching
  • ๐Ÿ” Deep Object Filtering - Search through nested objects up to configurable depths
  • โšก Zero Dependencies - Lightweight and production-ready (only Zod for runtime validation)
  • ๐Ÿ”’ Type-Safe - Built with strict TypeScript for maximum reliability
  • ๐ŸŽจ Multiple Strategies - String patterns, objects, predicates, operators, or custom comparators
  • ๐Ÿš€ Performance Optimized - Optional caching and regex compilation optimization
  • ๐Ÿงช Battle-Tested - 463+ tests ensuring reliability
  • ๐Ÿ“ฆ MongoDB-Style Operators - 18 operators for advanced filtering (v5.0.0+)
  • ๐Ÿค– Intelligent Autocomplete - Type-aware operator suggestions (v5.2.4+)
  • ๐Ÿ—๏ธ Nested Object Support - 4-level deep autocomplete (v5.2.4+)
  • ๐Ÿ’จ Lazy Evaluation - Process large datasets efficiently (v5.1.0+)
  • ๐Ÿ”€ Logical Operators - Complex queries with $and, $or, $not (v5.2.0+)

Why Choose This Library? โ€‹

  1. Flexible: Multiple ways to filter - choose what fits your use case
  2. Powerful: Handles complex scenarios that native filter can't
  3. Type-Safe: Full TypeScript support with strict typing
  4. Tested: Comprehensive test suite with 100% operator coverage
  5. Modern: Built with latest best practices and tools
  6. Documented: Extensive documentation with real-world examples

Installation & Setup โ€‹

Installation โ€‹

Choose your preferred package manager:

bash
# Using npm
npm install @mcabreradev/filter

# Using yarn
yarn add @mcabreradev/filter

# Using pnpm
pnpm add @mcabreradev/filter

TypeScript Configuration โ€‹

The library is built with TypeScript and requires Node.js >= 20. For optimal TypeScript experience, ensure your tsconfig.json includes:

json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "CommonJS",
    "lib": ["ES2022"],
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

Import Examples โ€‹

typescript
import { filter } from '@mcabreradev/filter';

// With types
import type { Expression, FilterOptions } from '@mcabreradev/filter';

CommonJS โ€‹

javascript
const { filter } = require('@mcabreradev/filter');

// In TypeScript
import filter = require('@mcabreradev/filter');

Default Import โ€‹

typescript
import filter from '@mcabreradev/filter';

Quick Start โ€‹

Get started with the most common use cases:

typescript
import { filter } from '@mcabreradev/filter';

const users = [
  { name: 'Alice', age: 30, city: 'Berlin', role: 'admin' },
  { name: 'Bob', age: 25, city: 'London', role: 'user' },
  { name: 'Charlie', age: 35, city: 'Berlin', role: 'user' }
];

// Simple string matching (searches all properties)
filter(users, 'Berlin');
// โ†’ [Alice, Charlie]

// Object-based filtering (exact match)
filter(users, { city: 'Berlin', age: 30 });
// โ†’ [Alice]

// Predicate function
filter(users, (user) => user.age > 28);
// โ†’ [Alice, Charlie]

// MongoDB-style operators (v5.0.0+)
filter(users, { age: { $gte: 25, $lt: 35 } });
// โ†’ [Bob, Alice]

Basic Usage โ€‹

String Filtering โ€‹

Filter arrays by searching for a string across all object properties.

Simple String Match โ€‹

typescript
const products = [
  { id: 1, name: 'Laptop', brand: 'Dell' },
  { id: 2, name: 'Mouse', brand: 'Logitech' },
  { id: 3, name: 'Keyboard', brand: 'Dell' }
];

// Find all products with "Dell" (case-insensitive by default)
filter(products, 'Dell');
// โ†’ [{ id: 1, name: 'Laptop', brand: 'Dell' }, { id: 3, name: 'Keyboard', brand: 'Dell' }]

filter(products, 'laptop');
// โ†’ [{ id: 1, name: 'Laptop', brand: 'Dell' }]

Case-Sensitive Matching โ€‹

typescript
// Case-sensitive search
filter(products, 'Dell', { caseSensitive: true });
// โ†’ Finds only exact "Dell" matches

filter(products, 'dell', { caseSensitive: true });
// โ†’ Returns [] (no match)

Searching Arrays of Primitives โ€‹

typescript
const tags = ['JavaScript', 'TypeScript', 'React', 'Node.js'];

filter(tags, 'script');
// โ†’ ['JavaScript', 'TypeScript']

filter(tags, 'React');
// โ†’ ['React']

Number Filtering โ€‹

Filter by numeric values.

typescript
const prices = [10, 25, 50, 100, 200];

filter(prices, 50);
// โ†’ [50]

// With objects
const items = [
  { name: 'Item A', price: 10 },
  { name: 'Item B', price: 25 },
  { name: 'Item C', price: 10 }
];

filter(items, 10);
// โ†’ [{ name: 'Item A', price: 10 }, { name: 'Item C', price: 10 }]

Boolean Filtering โ€‹

Filter by boolean values.

typescript
const tasks = [
  { title: 'Task 1', completed: true },
  { title: 'Task 2', completed: false },
  { title: 'Task 3', completed: true }
];

filter(tasks, true);
// โ†’ [{ title: 'Task 1', completed: true }, { title: 'Task 3', completed: true }]

filter(tasks, false);
// โ†’ [{ title: 'Task 2', completed: false }]

Wildcard Patterns โ€‹

SQL-like wildcard patterns for flexible string matching.

Percent Wildcard (%) โ€‹

The % wildcard matches zero or more characters.

Match at Beginning โ€‹

typescript
const users = [
  { name: 'Alice' },
  { name: 'Alex' },
  { name: 'Bob' }
];

filter(users, 'Al%');
// โ†’ [{ name: 'Alice' }, { name: 'Alex' }]

Match at End โ€‹

typescript
filter(users, '%ce');
// โ†’ [{ name: 'Alice' }]

Match in Middle โ€‹

typescript
const emails = [
  { email: 'user@gmail.com' },
  { email: 'admin@yahoo.com' },
  { email: 'test@gmail.com' }
];

filter(emails, '%gmail%');
// โ†’ [{ email: 'user@gmail.com' }, { email: 'test@gmail.com' }]

Multiple Wildcards โ€‹

typescript
const files = [
  { name: 'document.pdf' },
  { name: 'image.png' },
  { name: 'archive.tar.gz' }
];

filter(files, '%.p%');
// โ†’ [{ name: 'document.pdf' }, { name: 'image.png' }]

Underscore Wildcard (_) โ€‹

The _ wildcard matches exactly one character.

Single Character Match โ€‹

typescript
const codes = [
  { code: 'A1' },
  { code: 'A2' },
  { code: 'B1' },
  { code: 'AB1' }
];

filter(codes, 'A_');
// โ†’ [{ code: 'A1' }, { code: 'A2' }]

Position-Specific Matching โ€‹

typescript
const ids = [
  { id: 'user-101' },
  { id: 'user-102' },
  { id: 'admin-101' }
];

filter(ids, 'user-10_');
// โ†’ [{ id: 'user-101' }, { id: 'user-102' }]

Combining _ and % โ€‹

typescript
const patterns = [
  { text: 'test' },
  { text: 'testing' },
  { text: 'tested' }
];

filter(patterns, 'test__%');
// โ†’ [{ text: 'testing' }, { text: 'tested' }]

Negation (!) โ€‹

Use ! prefix to exclude matches.

Negating Strings โ€‹

typescript
const users = [
  { name: 'Alice', city: 'Berlin' },
  { name: 'Bob', city: 'London' },
  { name: 'Charlie', city: 'Berlin' }
];

filter(users, '!London');
// โ†’ [{ name: 'Alice', city: 'Berlin' }, { name: 'Charlie', city: 'Berlin' }]

Negating Patterns โ€‹

typescript
const emails = [
  { email: 'user@gmail.com' },
  { email: 'admin@company.com' },
  { email: 'test@gmail.com' }
];

filter(emails, '!%gmail%');
// โ†’ [{ email: 'admin@company.com' }]

Negation with Wildcards โ€‹

typescript
const files = [
  { name: 'doc.pdf' },
  { name: 'image.jpg' },
  { name: 'video.mp4' }
];

filter(files, '!%.pdf');
// โ†’ [{ name: 'image.jpg' }, { name: 'video.mp4' }]

Object-Based Filtering โ€‹

Filter by matching object properties.

Single Property Match โ€‹

typescript
const products = [
  { id: 1, name: 'Laptop', category: 'Electronics', price: 1200 },
  { id: 2, name: 'Desk', category: 'Furniture', price: 350 },
  { id: 3, name: 'Mouse', category: 'Electronics', price: 25 }
];

// Match by single property
filter(products, { category: 'Electronics' });
// โ†’ [{ id: 1, ... }, { id: 3, ... }]

filter(products, { price: 350 });
// โ†’ [{ id: 2, name: 'Desk', ... }]

Multiple Properties (AND Logic) โ€‹

All specified properties must match.

typescript
filter(products, { category: 'Electronics', price: 1200 });
// โ†’ [{ id: 1, name: 'Laptop', ... }]

filter(products, { category: 'Electronics', price: 25 });
// โ†’ [{ id: 3, name: 'Mouse', ... }]

Nested Objects โ€‹

Filter by nested object properties.

typescript
const users = [
  {
    name: 'Alice',
    address: { city: 'Berlin', country: 'Germany' },
    settings: { theme: 'dark', language: 'en' }
  },
  {
    name: 'Bob',
    address: { city: 'London', country: 'UK' },
    settings: { theme: 'light', language: 'en' }
  }
];

// Direct nested property match
filter(users, { address: { city: 'Berlin' } });
// โ†’ [{ name: 'Alice', ... }]

// Multiple nested properties
filter(users, {
  address: { country: 'Germany' },
  settings: { theme: 'dark' }
});
// โ†’ [{ name: 'Alice', ... }]

Mixing with Wildcards โ€‹

typescript
const items = [
  { name: 'Product A', code: 'PROD-001' },
  { name: 'Product B', code: 'PROD-002' },
  { name: 'Service A', code: 'SERV-001' }
];

filter(items, { code: 'PROD-%' });
// โ†’ [{ name: 'Product A', ... }, { name: 'Product B', ... }]

Predicate Functions โ€‹

Use custom functions for complex filtering logic.

Basic Predicates โ€‹

typescript
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Simple condition
filter(numbers, (n) => n > 5);
// โ†’ [6, 7, 8, 9, 10]

// Even numbers
filter(numbers, (n) => n % 2 === 0);
// โ†’ [2, 4, 6, 8, 10]

// Odd numbers
filter(numbers, (n) => n % 2 !== 0);
// โ†’ [1, 3, 5, 7, 9]

Advanced Predicates โ€‹

typescript
const products = [
  { name: 'Laptop', price: 1200, inStock: true, rating: 4.5 },
  { name: 'Mouse', price: 25, inStock: true, rating: 4.0 },
  { name: 'Keyboard', price: 75, inStock: false, rating: 4.2 }
];

// Complex conditions
filter(products, (product) =>
  product.price < 100 &&
  product.inStock &&
  product.rating >= 4.0
);
// โ†’ [{ name: 'Mouse', ... }]

// String operations
filter(products, (product) =>
  product.name.toLowerCase().includes('key')
);
// โ†’ [{ name: 'Keyboard', ... }]

// Date comparisons
const orders = [
  { id: 1, date: new Date('2025-01-15'), amount: 100 },
  { id: 2, date: new Date('2025-02-20'), amount: 200 },
  { id: 3, date: new Date('2025-03-10'), amount: 150 }
];

filter(orders, (order) =>
  order.date >= new Date('2025-02-01') &&
  order.amount > 150
);
// โ†’ [{ id: 2, ... }]

Type-Safe Predicates with TypeScript โ€‹

typescript
interface User {
  id: number;
  name: string;
  age: number;
  isActive: boolean;
}

const users: User[] = [
  { id: 1, name: 'Alice', age: 30, isActive: true },
  { id: 2, name: 'Bob', age: 25, isActive: false },
  { id: 3, name: 'Charlie', age: 35, isActive: true }
];

// Fully typed predicate
filter<User>(users, (user: User): boolean =>
  user.age > 28 && user.isActive
);
// โ†’ [{ id: 1, ... }, { id: 3, ... }]

Performance Considerations โ€‹

typescript
// โœ… Good: Simple, direct checks
filter(items, (item) => item.price > 100);

// โš ๏ธ Slower: Complex operations
filter(items, (item) => {
  const calculated = item.price * 1.2 + item.tax;
  return calculated > 100 && item.category.toLowerCase().includes('electronics');
});

// ๐Ÿ’ก Better: Use operators when possible
filter(items, {
  price: { $gt: 83.33 },  // Pre-calculated
  category: { $contains: 'electronics' }
});

MongoDB-Style Operators โ€‹

Version 5.0.0 introduces 13 powerful MongoDB-style operators for advanced filtering.

Comparison Operators โ€‹

$gt - Greater Than โ€‹

Returns items where the property value is greater than the specified value.

typescript
const products = [
  { name: 'Item A', price: 50 },
  { name: 'Item B', price: 150 },
  { name: 'Item C', price: 250 }
];

filter(products, { price: { $gt: 100 } });
// โ†’ [{ name: 'Item B', price: 150 }, { name: 'Item C', price: 250 }]

// With dates
const orders = [
  { id: 1, date: new Date('2025-01-15') },
  { id: 2, date: new Date('2025-02-20') },
  { id: 3, date: new Date('2025-03-10') }
];

filter(orders, { date: { $gt: new Date('2025-02-01') } });
// โ†’ [{ id: 2, ... }, { id: 3, ... }]

$gte - Greater Than or Equal โ€‹

typescript
filter(products, { price: { $gte: 150 } });
// โ†’ [{ name: 'Item B', price: 150 }, { name: 'Item C', price: 250 }]

// Date range start
filter(orders, {
  date: { $gte: new Date('2025-02-01') }
});
// โ†’ Includes orders from Feb 1st onwards

$lt - Less Than โ€‹

typescript
filter(products, { price: { $lt: 200 } });
// โ†’ [{ name: 'Item A', price: 50 }, { name: 'Item B', price: 150 }]

// Before a date
filter(orders, {
  date: { $lt: new Date('2025-03-01') }
});
// โ†’ Orders before March 1st

$lte - Less Than or Equal โ€‹

typescript
filter(products, { price: { $lte: 150 } });
// โ†’ [{ name: 'Item A', price: 50 }, { name: 'Item B', price: 150 }]

$eq - Equal โ€‹

typescript
const users = [
  { name: 'Alice', role: 'admin', age: 30 },
  { name: 'Bob', role: 'user', age: 25 },
  { name: 'Charlie', role: 'admin', age: 35 }
];

filter(users, { role: { $eq: 'admin' } });
// โ†’ [{ name: 'Alice', ... }, { name: 'Charlie', ... }]

// Equivalent to simple object matching
filter(users, { role: 'admin' });
// โ†’ Same result

$ne - Not Equal โ€‹

typescript
filter(users, { role: { $ne: 'admin' } });
// โ†’ [{ name: 'Bob', role: 'user', ... }]

filter(products, { price: { $ne: 50 } });
// โ†’ All products except Item A

Range Queries (Combining Operators) โ€‹

typescript
// Price between $100 and $200 (inclusive)
filter(products, {
  price: { $gte: 100, $lte: 200 }
});
// โ†’ [{ name: 'Item B', price: 150 }]

// Date range
filter(orders, {
  date: {
    $gte: new Date('2025-01-01'),
    $lte: new Date('2025-02-29')
  }
});
// โ†’ Orders in Q1 2025

// Excluding boundaries
filter(products, {
  price: { $gt: 50, $lt: 250 }
});
// โ†’ [{ name: 'Item B', price: 150 }]

Array Operators โ€‹

$in - Inclusion โ€‹

Returns items where the property value is in the specified array.

typescript
const products = [
  { id: 1, category: 'Electronics' },
  { id: 2, category: 'Furniture' },
  { id: 3, category: 'Books' },
  { id: 4, category: 'Clothing' }
];

filter(products, {
  category: { $in: ['Electronics', 'Books'] }
});
// โ†’ [{ id: 1, ... }, { id: 3, ... }]

// With numbers
const items = [
  { id: 1, status: 200 },
  { id: 2, status: 404 },
  { id: 3, status: 500 }
];

filter(items, {
  status: { $in: [200, 201, 202] }
});
// โ†’ [{ id: 1, status: 200 }]

// Mixed types
filter(products, {
  id: { $in: [1, 3, 5, 7] }
});
// โ†’ Products with IDs 1 and 3

$nin - Not In (Exclusion) โ€‹

typescript
filter(products, {
  category: { $nin: ['Furniture', 'Clothing'] }
});
// โ†’ [{ id: 1, category: 'Electronics' }, { id: 3, category: 'Books' }]

// Exclude multiple statuses
filter(items, {
  status: { $nin: [404, 500] }
});
// โ†’ Only successful responses

$contains - Array Contains Value โ€‹

Checks if an array property contains a specific value.

typescript
const products = [
  { name: 'Laptop', tags: ['computer', 'portable', 'gaming'] },
  { name: 'Mouse', tags: ['computer', 'accessory'] },
  { name: 'Desk', tags: ['office', 'furniture'] }
];

filter(products, {
  tags: { $contains: 'computer' }
});
// โ†’ [{ name: 'Laptop', ... }, { name: 'Mouse', ... }]

filter(products, {
  tags: { $contains: 'gaming' }
});
// โ†’ [{ name: 'Laptop', ... }]

$size - Array Length โ€‹

Returns items where the array has a specific length.

typescript
filter(products, {
  tags: { $size: 2 }
});
// โ†’ [{ name: 'Mouse', tags: ['computer', 'accessory'] }]

filter(products, {
  tags: { $size: 3 }
});
// โ†’ [{ name: 'Laptop', tags: ['computer', 'portable', 'gaming'] }]

// Find items with no tags
const allProducts = [
  ...products,
  { name: 'Unknown', tags: [] }
];

filter(allProducts, { tags: { $size: 0 } });
// โ†’ [{ name: 'Unknown', tags: [] }]

String Operators โ€‹

All string operators are case-insensitive by default (configurable).

$startsWith - Starts With โ€‹

typescript
const users = [
  { name: 'Alice', email: 'alice@gmail.com' },
  { name: 'Bob', email: 'bob@yahoo.com' },
  { name: 'Alex', email: 'alex@gmail.com' }
];

filter(users, { name: { $startsWith: 'Al' } });
// โ†’ [{ name: 'Alice', ... }, { name: 'Alex', ... }]

// Email domain filtering
filter(users, {
  email: { $startsWith: 'alice' }
});
// โ†’ [{ name: 'Alice', ... }]

// Case-sensitive
filter(users, {
  name: { $startsWith: 'al' }
}, { caseSensitive: true });
// โ†’ [] (no match)

$endsWith - Ends With โ€‹

typescript
filter(users, {
  email: { $endsWith: 'gmail.com' }
});
// โ†’ [{ name: 'Alice', ... }, { name: 'Alex', ... }]

// File extensions
const files = [
  { name: 'document.pdf' },
  { name: 'image.jpg' },
  { name: 'video.mp4' }
];

filter(files, {
  name: { $endsWith: '.pdf' }
});
// โ†’ [{ name: 'document.pdf' }]

filter(files, {
  name: { $endsWith: '.jpg' }
});
// โ†’ [{ name: 'image.jpg' }]

$contains - String Contains (Substring) โ€‹

typescript
filter(users, {
  email: { $contains: 'gmail' }
});
// โ†’ [{ name: 'Alice', ... }, { name: 'Alex', ... }]

filter(users, {
  name: { $contains: 'li' }
});
// โ†’ [{ name: 'Alice', ... }]

// URL filtering
const links = [
  { url: 'https://example.com/api/users' },
  { url: 'https://example.com/admin/users' },
  { url: 'https://example.com/api/products' }
];

filter(links, {
  url: { $contains: '/api/' }
});
// โ†’ API endpoints only

Regex Operators โ€‹

New in v5.2.0 - Pattern matching with regular expressions.

$regex - Regular Expression Match โ€‹

Match strings using regular expressions.

typescript
const users = [
  { email: 'user@gmail.com' },
  { email: 'admin@company.com' },
  { email: 'test@GMAIL.com' }
];

// Case-insensitive email matching
filter(users, {
  email: { $regex: /@gmail\.com$/i }
});
// โ†’ [{ email: 'user@gmail.com' }, { email: 'test@GMAIL.com' }]

// Pattern validation
const products = [
  { sku: 'PROD-001-A' },
  { sku: 'PROD-002-B' },
  { sku: 'SERV-001-A' }
];

filter(products, {
  sku: { $regex: /^PROD-\d{3}-[A-Z]$/ }
});
// โ†’ [{ sku: 'PROD-001-A' }, { sku: 'PROD-002-B' }]

// Phone number validation
const contacts = [
  { phone: '+1-555-0100' },
  { phone: '555-0200' },
  { phone: '+1-555-0300' }
];

filter(contacts, {
  phone: { $regex: /^\+1-\d{3}-\d{4}$/ }
});
// โ†’ [{ phone: '+1-555-0100' }, { phone: '+1-555-0300' }]

$match - Alias for $regex โ€‹

$match is an alias for $regex for more intuitive naming:

typescript
// These are equivalent:
filter(users, { email: { $regex: /^admin/ } });
filter(users, { email: { $match: /^admin/ } });

Complex Patterns โ€‹

typescript
// URL validation
const links = [
  { url: 'https://example.com/api/v1/users' },
  { url: 'http://test.com/admin' },
  { url: 'https://example.com/api/v2/products' }
];

filter(links, {
  url: { $regex: /^https:\/\/.*\/api\/v[12]\// }
});
// โ†’ API v1 and v2 endpoints with HTTPS

// Date format matching (YYYY-MM-DD)
const records = [
  { date: '2025-01-15' },
  { date: '01/15/2025' },
  { date: '2025-02-20' }
];

filter(records, {
  date: { $regex: /^\d{4}-\d{2}-\d{2}$/ }
});
// โ†’ [{ date: '2025-01-15' }, { date: '2025-02-20' }]

Performance Note

Regex operators are powerful but slower than simple string operators. Use $startsWith, $endsWith, or $contains when possible for better performance.

typescript
// โš ๏ธ Slower: Regex
filter(users, { email: { $regex: /@gmail\.com$/ } });

// โœ… Faster: String operator
filter(users, { email: { $endsWith: '@gmail.com' } });

Logical Operators โ€‹

New in v5.2.0 - Combine multiple conditions with logical operators for complex queries.

$and - All Conditions Must Match โ€‹

typescript
const products = [
  { name: 'Laptop', price: 1200, rating: 4.5, inStock: true },
  { name: 'Mouse', price: 25, rating: 4.0, inStock: true },
  { name: 'Monitor', price: 450, rating: 4.7, inStock: false }
];

// Find products that are affordable AND highly rated AND in stock
filter(products, {
  $and: [
    { price: { $lte: 500 } },
    { rating: { $gte: 4.5 } },
    { inStock: true }
  ]
});
// โ†’ [] (Monitor is not in stock, Mouse rating is 4.0)

Implicit AND

Multiple properties at the same level use implicit AND logic:

typescript
// These are equivalent:
filter(products, { price: { $lte: 500 }, inStock: true });
filter(products, { $and: [{ price: { $lte: 500 } }, { inStock: true }] });

$or - Any Condition Must Match โ€‹

typescript
const users = [
  { name: 'Alice', age: 17, isPremium: false },
  { name: 'Bob', age: 25, isPremium: true },
  { name: 'Charlie', age: 30, isPremium: false }
];

// Find users who are either adults OR premium members
filter(users, {
  $or: [
    { age: { $gte: 18 } },
    { isPremium: true }
  ]
});
// โ†’ [{ name: 'Bob', ... }, { name: 'Charlie', ... }]

$not - Negation โ€‹

typescript
// Find products that are NOT out of stock
filter(products, {
  $not: {
    inStock: false
  }
});
// โ†’ [{ name: 'Laptop', ... }, { name: 'Mouse', ... }]

// Complex negation: NOT (cheap OR low-rated)
filter(products, {
  $not: {
    $or: [
      { price: { $lt: 100 } },
      { rating: { $lt: 4.0 } }
    ]
  }
});
// โ†’ [{ name: 'Laptop', ... }, { name: 'Monitor', ... }]

Combining Logical Operators โ€‹

typescript
// Complex e-commerce query:
// (High rating OR popular brand) AND in stock AND affordable
filter(products, {
  $and: [
    {
      $or: [
        { rating: { $gte: 4.5 } },
        { brand: { $in: ['Apple', 'Samsung', 'Sony'] } }
      ]
    },
    { inStock: true },
    { price: { $lte: 1000 } }
  ]
});

// Clearance items: On sale BUT NOT (out of stock OR discontinued)
filter(products, {
  discount: { $gt: 0 },
  $not: {
    $or: [
      { inStock: false },
      { tags: { $contains: 'discontinued' } }
    ]
  }
});

Nested Logical Operators โ€‹

typescript
// Find users in specific age ranges with certain conditions
filter(users, {
  $or: [
    {
      $and: [
        { age: { $gte: 18, $lt: 25 } },
        { status: 'student' }
      ]
    },
    {
      $and: [
        { age: { $gte: 25, $lt: 65 } },
        { status: 'employed' }
      ]
    },
    {
      $and: [
        { age: { $gte: 65 } },
        { status: 'retired' }
      ]
    }
  ]
});

Combining Operators โ€‹

Multiple Operators on Same Property โ€‹

typescript
const products = [
  { name: 'Item A', price: 50 },
  { name: 'Item B', price: 150 },
  { name: 'Item C', price: 250 },
  { name: 'Item D', price: 300 }
];

// Price between 100 and 200, excluding 150
filter(products, {
  price: {
    $gte: 100,
    $lte: 200,
    $ne: 150
  }
});
// โ†’ [] (Item B is excluded by $ne)

// More realistic: 100-300 range, excluding 250
filter(products, {
  price: {
    $gte: 100,
    $lte: 300,
    $ne: 250
  }
});
// โ†’ [{ name: 'Item B', ... }, { name: 'Item D', ... }]

Multiple Operators on Different Properties โ€‹

typescript
const products = [
  { name: 'Laptop Pro', price: 1200, category: 'Electronics', rating: 4.5 },
  { name: 'Mouse', price: 25, category: 'Accessories', rating: 4.0 },
  { name: 'Monitor', price: 450, category: 'Electronics', rating: 4.7 },
  { name: 'Desk', price: 350, category: 'Furniture', rating: 4.2 }
];

// Complex multi-condition filter
filter(products, {
  price: { $gte: 100, $lte: 500 },
  category: { $in: ['Electronics', 'Accessories'] },
  name: { $startsWith: 'M' },
  rating: { $gte: 4.0 }
});
// โ†’ [{ name: 'Monitor', ... }]

// E-commerce: Affordable electronics in stock
const inventory = [
  { name: 'Product A', price: 299, category: 'Electronics', inStock: true },
  { name: 'Product B', price: 599, category: 'Electronics', inStock: true },
  { name: 'Product C', price: 199, category: 'Electronics', inStock: false }
];

filter(inventory, {
  price: { $lte: 400 },
  category: { $eq: 'Electronics' },
  inStock: { $eq: true }
});
// โ†’ [{ name: 'Product A', ... }]

Intelligent Autocomplete โ€‹

New in v5.2.4 - TypeScript provides intelligent, type-aware operator suggestions that improve developer experience and prevent errors at compile time.

Overview โ€‹

The type system analyzes each property of your interface and suggests only valid operators for that specific type. No more guessing which operators work with which data types!

Type-Aware Suggestions โ€‹

When you type in your editor, TypeScript shows only relevant operators:

typescript
interface User {
  name: string;
  age: number;
  tags: string[];
  isActive: boolean;
  createdAt: Date;
}

const users: User[] = [];

// When you type: filter(users, { age: { $
// Press Ctrl+Space (or Cmd+Space on Mac)
// TypeScript shows ONLY:
// โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
// โ”‚ โœ“ $gt     - Greater than            โ”‚
// โ”‚ โœ“ $gte    - Greater than or equal   โ”‚
// โ”‚ โœ“ $lt     - Less than               โ”‚
// โ”‚ โœ“ $lte    - Less than or equal      โ”‚
// โ”‚ โœ“ $eq     - Equal                   โ”‚
// โ”‚ โœ“ $ne     - Not equal               โ”‚
// โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

// You WON'T see $startsWith, $contains, etc.
// (they don't make sense for numbers!)

Operator Mapping by Type โ€‹

TypeAvailable Operators
string$startsWith, $endsWith, $contains, $regex, $match, $eq, $ne
number$gt, $gte, $lt, $lte, $eq, $ne
Date$gt, $gte, $lt, $lte, $eq, $ne
Array\<T>$in, $nin, $contains, $size
boolean$eq, $ne
other$eq, $ne

Nested Object Autocomplete โ€‹

New in v5.2.4 - Autocomplete works up to 4 levels deep for nested objects:

typescript
interface User {
  name: string;
  address: {
    city: string;
    coordinates: {
      lat: number;
      lng: number;
    };
  };
  settings: {
    privacy: {
      showEmail: boolean;
    };
  };
}

const users: User[] = [];

// โœ… Level 1: Root properties
filter(users, {
  name: { $startsWith: 'John' }  // Autocompletes string operators
});

// โœ… Level 2: Nested objects
filter(users, {
  address: {
    city: { $startsWith: 'New' }  // Autocompletes string operators
  }
});

// โœ… Level 3: Deeply nested objects
filter(users, {
  address: {
    coordinates: {
      lat: { $gte: -90, $lte: 90 }  // Autocompletes number operators
    }
  }
});

// โœ… Level 4: Very deeply nested objects
filter(users, {
  settings: {
    privacy: {
      showEmail: { $eq: true }  // Autocompletes boolean operators
    }
  }
});

Type Safety โ€‹

TypeScript prevents errors at compile time:

typescript
interface User {
  age: number;
  name: string;
}

// โŒ Error: $startsWith is not valid for numbers
filter(users, {
  age: {
    $startsWith: '25'  // TypeScript marks this as an error
  }
});

// โœ… Correct usage
filter(users, {
  age: { $gte: 25 },           // Number operators
  name: { $startsWith: 'John' } // String operators
});

Editor Support โ€‹

Autocomplete works in any editor with TypeScript support:

  • VS Code/Cursor: Press Ctrl+Space (Windows/Linux) or Cmd+Space (Mac)
  • WebStorm/IntelliJ: Autocomplete appears automatically
  • Vim/Neovim: With LSP configured (coc.nvim, nvim-lsp)
  • Sublime Text: With LSP-typescript
  • Emacs: With lsp-mode or eglot

Benefits โ€‹

  1. Discovery: Discover available operators without consulting documentation
  2. Error Prevention: TypeScript prevents the use of incorrect operators
  3. Productivity: Write code faster with intelligent suggestions
  4. Maintainability: Code is easier to understand and maintain
  5. Safe Refactoring: Type changes propagate automatically
  6. Zero Cost: Pure TypeScript feature, no runtime overhead

Lazy Evaluation โ€‹

New in v5.1.0 - Process large datasets efficiently with generators and lazy evaluation. Stop processing early and save resources.

Overview โ€‹

Lazy evaluation allows you to process items on-demand rather than filtering the entire array upfront. This approach:

  • 500x faster for early exits (finding first N matches)
  • Reduces memory footprint - Only processes items as needed
  • Improves performance - Stops early when conditions are met
  • Enables infinite streams - Works with generators and async iterables
  • Supports chunked processing - Process data in manageable batches

filterLazy โ€‹

Returns a lazy iterator that yields filtered items on-demand.

Signature:

typescript
function filterLazy<T>(
  iterable: Iterable<T>,
  expression: Expression<T>,
  options?: FilterOptions
): Generator<T, void, undefined>

Example:

typescript
import { filterLazy } from '@mcabreradev/filter';

const millionRecords = [/* 1,000,000 items */];

// Lazy evaluation - items processed on-demand
const filtered = filterLazy(millionRecords, {
  status: 'active',
  score: { $gte: 90 }
});

// Consume only what you need
for (const item of filtered) {
  console.log(item);
  if (someCondition) break; // Stop early - remaining items never processed!
}

filterFirst โ€‹

Find the first N matching items and stop processing.

Signature:

typescript
function filterFirst<T>(
  iterable: Iterable<T>,
  expression: Expression<T>,
  limit: number,
  options?: FilterOptions
): T[]

Example:

typescript
import { filterFirst } from '@mcabreradev/filter';

// Find first 10 high-value transactions
const topTransactions = filterFirst(
  millionTransactions,
  { amount: { $gte: 10000 }, status: 'completed' },
  10  // Stop after finding 10 matches
);
// โ†’ 500x faster than filtering entire array!

Performance Benefits โ€‹

Performance Comparison โ€‹

typescript
const largeDataset = Array.from({ length: 1_000_000 }, (_, i) => ({
  id: i,
  value: Math.random() * 1000,
  status: i % 2 === 0 ? 'active' : 'inactive'
}));

// โŒ Slow: Process entire array
console.time('eager');
const eager = filter(largeDataset, { status: 'active', value: { $gte: 900 } });
const first10Eager = eager.slice(0, 10);
console.timeEnd('eager');  // ~250ms

// โœ… Fast: Stop after finding 10
console.time('lazy');
const first10Lazy = filterFirst(
  largeDataset,
  { status: 'active', value: { $gte: 900 } },
  10
);
console.timeEnd('lazy');  // ~0.5ms (500x faster!)

Real-World Use Cases โ€‹

Pagination โ€‹

typescript
function getPage(
  data: Item[],
  page: number,
  pageSize: number,
  filters: Expression<Item>
) {
  const skip = page * pageSize;
  const lazy = filterLazy(data, filters);

  let count = 0;
  const results: Item[] = [];

  for (const item of lazy) {
    if (count >= skip && results.length < pageSize) {
      results.push(item);
    }
    count++;
    if (results.length === pageSize) break;  // Stop when page is full
  }

  return results;
}

Search with Limit โ€‹

typescript
function searchProducts(query: string, limit: number = 20) {
  return filterFirst(
    products,
    { name: { $contains: query }, inStock: true },
    limit
  );
}

Combining with Caching โ€‹

typescript
// Lazy evaluation + caching for repeated queries
const results = filterFirst(
  largeDataset,
  { category: 'Electronics', price: { $lte: 1000 } },
  50,
  { enableCache: true }
);
// First run: ~15ms (early exit)
// Cached run: ~0.01ms (instant!)

Performance Metrics โ€‹

OperationEager FilterLazy FilterSpeedup
Find first 10 (1M items)250ms0.5ms500x
Find first 100 (1M items)250ms5ms50x
Process until condition250msVariable10-500x
Memory usage (1M items)80MB<1MB80x less

Configuration API โ€‹

Customize filter behavior with configuration options.

caseSensitive โ€‹

Controls case sensitivity for string matching.

Type: booleanDefault: false

typescript
const users = [
  { name: 'Alice' },
  { name: 'ALICE' },
  { name: 'alice' }
];

// Case-insensitive (default)
filter(users, 'alice');
// โ†’ All three users

filter(users, 'ALICE');
// โ†’ All three users

// Case-sensitive
filter(users, 'alice', { caseSensitive: true });
// โ†’ [{ name: 'alice' }]

filter(users, 'ALICE', { caseSensitive: true });
// โ†’ [{ name: 'ALICE' }]

Impact on String Operators:

typescript
const emails = [
  { email: 'User@Example.com' },
  { email: 'admin@example.com' }
];

// Case-insensitive
filter(emails, {
  email: { $startsWith: 'user' }
});
// โ†’ [{ email: 'User@Example.com' }]

// Case-sensitive
filter(emails, {
  email: { $startsWith: 'user' }
}, { caseSensitive: true });
// โ†’ [] (no match)

maxDepth โ€‹

Sets maximum depth for nested object comparison.

Type: numberDefault: 3Range: 1-10

typescript
const data = [
  {
    level1: {
      level2: {
        level3: {
          level4: {
            value: 'deep'
          }
        }
      }
    }
  }
];

// Default depth (3)
filter(data, {
  level1: {
    level2: {
      level3: { value: 'deep' }
    }
  }
});
// โ†’ May not match if depth exceeded

// Increase depth
filter(data, {
  level1: {
    level2: {
      level3: {
        level4: { value: 'deep' }
      }
    }
  }
}, { maxDepth: 5 });
// โ†’ Matches

Performance Note: Higher depth values may impact performance with deeply nested objects.

enableCache โ€‹

Enables multi-layer memoization for maximum performance.

Type: booleanDefault: falseNew in: v5.2.0 (enhanced implementation)

typescript
const largeDataset = [/* 10,000 items */];

// Without cache
const result1 = filter(largeDataset, { category: 'Electronics' });
const result2 = filter(largeDataset, { category: 'Electronics' }); // Recalculates

// With cache
const result1 = filter(largeDataset, { category: 'Electronics' }, { enableCache: true });
const result2 = filter(largeDataset, { category: 'Electronics' }, { enableCache: true });
// โ†’ Second call is 530x faster! โšก

Cache Layers:

  1. Result Cache - Complete filter results (WeakMap)
  2. Predicate Cache - Compiled predicates (LRU + TTL)
  3. Regex Cache - Compiled patterns (Map)

When to Enable:

  • โœ… Large datasets (>1,000 items)
  • โœ… Repeated identical queries
  • โœ… Complex expressions with regex
  • โœ… Read-heavy workloads
  • โœ… Dashboard/analytics views

When NOT to Enable:

  • โŒ Frequently changing data
  • โŒ One-time queries
  • โŒ Memory-constrained environments
  • โŒ Unique expressions every time

Performance Impact:

typescript
// Benchmark: 10,000 items
const products = [/* 10,000 products */];
const query = { price: { $gte: 100, $lte: 500 }, inStock: true };

// First run
console.time('first');
filter(products, query, { enableCache: true });
console.timeEnd('first'); // ~5.3ms

// Second run (cached)
console.time('cached');
filter(products, query, { enableCache: true });
console.timeEnd('cached'); // ~0.01ms (530x faster!)

Cache Management:

typescript
import { filter, clearFilterCache, getFilterCacheStats } from '@mcabreradev/filter';

// Get cache statistics
const stats = getFilterCacheStats();
console.log(stats);
// โ†’ { predicateCacheSize: 45, regexCacheSize: 12 }

// Clear all caches
clearFilterCache();

// Automatic cleanup with WeakMap
let data = [/* large dataset */];
filter(data, query, { enableCache: true });
data = null; // Cache automatically cleared โœจ

Real-World Example:

typescript
class ProductService {
  private products: Product[];

  constructor(products: Product[]) {
    this.products = products;
  }

  // All methods use caching
  getElectronics() {
    return filter(
      this.products,
      { category: 'Electronics' },
      { enableCache: true }
    );
  }

  getInStock() {
    return filter(
      this.products,
      { inStock: true },
      { enableCache: true }
    );
  }

  // Clear cache when data updates
  refreshProducts(newProducts: Product[]) {
    this.products = newProducts;
    clearFilterCache();
  }
}

const service = new ProductService(products);

// First calls: normal speed
service.getElectronics(); // 5.3ms
service.getInStock();     // 4.8ms

// User navigates between views...
// Subsequent calls: instant!
service.getElectronics(); // 0.01ms โšก
service.getInStock();     // 0.01ms โšก

Advanced: Combining with Lazy Evaluation:

typescript
import { filterFirst } from '@mcabreradev/filter';

// Find first 10 matches with caching
const topResults = filterFirst(
  millionRecords,
  { status: 'active', score: { $gte: 90 } },
  10,
  { enableCache: true }
);
// First run: ~15ms (early exit)
// Cached run: ~0.01ms (instant!)

Memory Usage:

Cache TypeMemory per EntryMax Memory
Result Cache~8 bytesUnlimited*
Predicate Cache~200 bytes~100 KB
Regex Cache~150 bytes~150 KB

*WeakMap automatically garbage collects

See also:

customComparator โ€‹

Provide custom comparison logic.

Type: (actual: unknown, expected: unknown) => booleanDefault: Case-insensitive substring matching

typescript
// Custom exact match comparator
const exactMatch = (actual: unknown, expected: unknown) => actual === expected;

filter(users, 'Alice', { customComparator: exactMatch });
// โ†’ Exact matches only

// Custom numeric comparator with tolerance
const numericTolerance = (actual: unknown, expected: unknown) => {
  if (typeof actual === 'number' && typeof expected === 'number') {
    return Math.abs(actual - expected) < 0.01;
  }
  return actual === expected;
};

const measurements = [
  { value: 10.001 },
  { value: 10.002 },
  { value: 11.0 }
];

filter(measurements, 10, { customComparator: numericTolerance });
// โ†’ [{ value: 10.001 }, { value: 10.002 }]

// Custom locale-aware string comparator
const localeCompare = (actual: unknown, expected: unknown) => {
  if (typeof actual === 'string' && typeof expected === 'string') {
    return actual.localeCompare(expected, 'en', { sensitivity: 'base' }) === 0;
  }
  return actual === expected;
};

Mixing Syntax Patterns โ€‹

Combine different filtering syntaxes for maximum flexibility.

Operators + Simple Equality โ€‹

typescript
const products = [
  { name: 'Laptop', price: 1200, category: 'Electronics' },
  { name: 'Monitor', price: 450, category: 'Electronics' },
  { name: 'Desk', price: 350, category: 'Furniture' }
];

filter(products, {
  category: 'Electronics',    // Simple equality
  price: { $gte: 400 }        // Operator
});
// โ†’ [{ name: 'Laptop', ... }, { name: 'Monitor', ... }]

Operators + Wildcards โ€‹

typescript
const files = [
  { name: 'report-2025.pdf', size: 1024 },
  { name: 'image-2025.jpg', size: 2048 },
  { name: 'video-2025.mp4', size: 10240 }
];

filter(files, {
  name: '%2025%',           // Wildcard
  size: { $lt: 5000 }       // Operator
});
// โ†’ [{ name: 'report-2025.pdf', ... }, { name: 'image-2025.jpg', ... }]

Operators + Negation โ€‹

typescript
const users = [
  { name: 'Alice', role: 'admin', age: 30 },
  { name: 'Bob', role: 'user', age: 25 },
  { name: 'Charlie', role: 'admin', age: 35 }
];

filter(users, {
  role: '!user',           // Negation
  age: { $gte: 30 }        // Operator
});
// โ†’ [{ name: 'Alice', ... }, { name: 'Charlie', ... }]

Complex Combination โ€‹

typescript
const products = [
  {
    name: 'Gaming Laptop',
    price: 1500,
    category: 'Electronics',
    tags: ['gaming', 'portable'],
    inStock: true
  },
  {
    name: 'Office Laptop',
    price: 800,
    category: 'Electronics',
    tags: ['business', 'portable'],
    inStock: true
  },
  {
    name: 'Gaming Desktop',
    price: 2000,
    category: 'Electronics',
    tags: ['gaming', 'powerful'],
    inStock: false
  }
];

filter(products, {
  category: 'Electronics',              // Simple equality
  name: '%Laptop%',                     // Wildcard
  price: { $gte: 700, $lte: 1600 },   // Range operators
  tags: { $contains: 'gaming' },       // Array operator
  inStock: { $eq: true }               // Boolean operator
});
// โ†’ [{ name: 'Gaming Laptop', ... }]

TypeScript Integration โ€‹

Full TypeScript support with strict typing.

Type Definitions โ€‹

typescript
import type {
  Expression,
  PrimitiveExpression,
  PredicateFunction,
  ObjectExpression,
  FilterOptions,
  FilterConfig,
  Comparator,
  ComparisonOperators,
  ArrayOperators,
  StringOperators,
  OperatorExpression
} from '@mcabreradev/filter';

Generic Type Parameter โ€‹

typescript
interface Product {
  id: number;
  name: string;
  price: number;
  category: string;
  tags: string[];
  inStock: boolean;
}

const products: Product[] = [
  { id: 1, name: 'Laptop', price: 1200, category: 'Electronics', tags: ['computer'], inStock: true },
  // ...
];

// Type-safe filtering
const result = filter<Product>(products, {
  price: { $gte: 100 }
});
// result is Product[]

// TypeScript catches errors
filter<Product>(products, {
  price: { $gte: '100' }  // โŒ Error: Type 'string' not assignable to 'number | Date'
});

filter<Product>(products, {
  invalidProp: 'value'     // โŒ Error: Property 'invalidProp' does not exist
});

Type Inference โ€‹

typescript
// TypeScript infers types automatically
const numbers = [1, 2, 3, 4, 5];
const filtered = filter(numbers, (n) => n > 3);
// filtered is number[]

const users = [
  { name: 'Alice', age: 30 },
  { name: 'Bob', age: 25 }
];
const adults = filter(users, (user) => user.age >= 18);
// adults is { name: string; age: number; }[]

Custom Types with Operators โ€‹

typescript
interface User {
  id: number;
  name: string;
  email: string;
  age: number;
  roles: string[];
  createdAt: Date;
}

// Type-safe operator expressions
const ageFilter: ComparisonOperators = {
  $gte: 18,
  $lte: 65
};

const roleFilter: ArrayOperators = {
  $contains: 'admin'
};

const emailFilter: StringOperators = {
  $endsWith: '@company.com'
};

// Combine in filter
filter<User>(users, {
  age: ageFilter,
  roles: roleFilter,
  email: emailFilter
});

Predicate Type Safety โ€‹

typescript
interface Product {
  id: number;
  name: string;
  price: number;
}

const products: Product[] = [/* ... */];

// Fully typed predicate
filter<Product>(products, (product: Product): boolean => {
  // TypeScript provides autocomplete and type checking
  return product.price > 100 && product.name.includes('Pro');
});

// Arrow function with implicit return
filter<Product>(products, (p) => p.price > 100);

Expression Type โ€‹

typescript
// Define reusable expressions
const electronicFilter: Expression<Product> = {
  category: 'Electronics',
  price: { $lte: 1000 }
};

const premiumFilter: Expression<Product> = (product) =>
  product.price > 500 && product.rating >= 4.5;

// Use in filters
filter<Product>(products, electronicFilter);
filter<Product>(products, premiumFilter);

FilterOptions Type โ€‹

typescript
const options: FilterOptions = {
  caseSensitive: true,
  maxDepth: 5,
  enableCache: false
};

filter(data, expression, options);

// Partial options
const partialOptions: FilterOptions = {
  caseSensitive: true
  // Other options use defaults
};

Real-World Examples โ€‹

Comprehensive examples for common use cases.

E-commerce Product Filtering โ€‹

typescript
interface Product {
  id: number;
  name: string;
  price: number;
  category: string;
  subcategory: string;
  brand: string;
  rating: number;
  reviews: number;
  inStock: boolean;
  tags: string[];
  discount: number;
  images: string[];
  createdAt: Date;
}

const products: Product[] = [
  {
    id: 1,
    name: 'Dell XPS 15 Laptop',
    price: 1499,
    category: 'Electronics',
    subcategory: 'Computers',
    brand: 'Dell',
    rating: 4.7,
    reviews: 1250,
    inStock: true,
    tags: ['laptop', 'gaming', 'professional'],
    discount: 10,
    images: ['img1.jpg', 'img2.jpg'],
    createdAt: new Date('2025-01-15')
  },
  // ... more products
];

// Find affordable laptops with good ratings
const affordableLaptops = filter(products, {
  category: 'Electronics',
  subcategory: 'Computers',
  price: { $lte: 1500 },
  rating: { $gte: 4.5 },
  inStock: { $eq: true }
});

// Products on sale (discount > 0)
const onSale = filter(products, {
  discount: { $gt: 0 },
  inStock: true
});

// New arrivals (last 30 days)
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

const newArrivals = filter(products, {
  createdAt: { $gte: thirtyDaysAgo },
  inStock: true
});

// Premium products by specific brands
const premiumProducts = filter(products, {
  brand: { $in: ['Apple', 'Dell', 'HP'] },
  price: { $gte: 1000 },
  rating: { $gte: 4.5 }
});

// Products with many reviews
const popularProducts = filter(products, {
  reviews: { $gte: 1000 },
  rating: { $gte: 4.0 }
});

// Search by keyword in name
const searchResults = filter(products, {
  name: { $contains: 'laptop' },
  price: { $lte: 2000 }
});

User Management System โ€‹

typescript
interface User {
  id: number;
  username: string;
  email: string;
  age: number;
  roles: string[];
  isActive: boolean;
  department: string;
  salary: number;
  hireDate: Date;
  lastLogin: Date;
}

const users: User[] = [/* ... */];

// Active admin users
const activeAdmins = filter(users, {
  roles: { $contains: 'admin' },
  isActive: { $eq: true }
});

// Users hired this year
const thisYear = new Date().getFullYear();
const newHires = filter(users, {
  hireDate: { $gte: new Date(`${thisYear}-01-01`) }
});

// High-salary employees in Engineering
const topEngineers = filter(users, {
  department: 'Engineering',
  salary: { $gte: 100000 }
});

// Inactive users (no login in 90 days)
const ninetyDaysAgo = new Date();
ninetyDaysAgo.setDate(ninetyDaysAgo.getDate() - 90);

const inactiveUsers = filter(users, {
  lastLogin: { $lt: ninetyDaysAgo },
  isActive: true
});

// Users by email domain
const companyUsers = filter(users, {
  email: { $endsWith: '@company.com' }
});

// Users with multiple roles
const multiRoleUsers = filter(users, {
  roles: { $size: { $gte: 2 } }
});

// Adult users in specific departments
const eligibleUsers = filter(users, {
  age: { $gte: 18, $lte: 65 },
  department: { $in: ['Engineering', 'Sales', 'Marketing'] },
  isActive: true
});

Data Analytics & Reporting โ€‹

typescript
interface Transaction {
  id: string;
  amount: number;
  currency: string;
  status: 'pending' | 'completed' | 'failed' | 'refunded';
  customerId: string;
  date: Date;
  category: string;
  paymentMethod: string;
  country: string;
}

const transactions: Transaction[] = [/* ... */];

// Successful transactions above threshold
const highValueTransactions = filter(transactions, {
  amount: { $gte: 10000 },
  status: 'completed'
});

// Failed transactions for investigation
const failedPayments = filter(transactions, {
  status: 'failed',
  date: {
    $gte: new Date('2025-01-01'),
    $lte: new Date('2025-12-31')
  }
});

// International transactions
const internationalSales = filter(transactions, {
  country: { $nin: ['USA', 'US'] },
  status: 'completed'
});

// Refund analysis
const refunds = filter(transactions, {
  status: 'refunded',
  amount: { $gte: 100 }
});

// Payment method distribution
const cardPayments = filter(transactions, {
  paymentMethod: { $startsWith: 'card' },
  status: { $in: ['completed', 'pending'] }
});

// Monthly revenue (Q1 example)
const q1Revenue = filter(transactions, {
  date: {
    $gte: new Date('2025-01-01'),
    $lte: new Date('2025-03-31')
  },
  status: 'completed'
});

const totalRevenue = q1Revenue.reduce((sum, t) => sum + t.amount, 0);

Search Functionality โ€‹

typescript
interface Article {
  id: number;
  title: string;
  content: string;
  author: string;
  tags: string[];
  category: string;
  publishDate: Date;
  views: number;
  likes: number;
  status: 'draft' | 'published' | 'archived';
}

const articles: Article[] = [/* ... */];

// Full-text search (title + content)
const searchTerm = 'typescript';
const searchResults = filter(articles, (article) =>
  article.title.toLowerCase().includes(searchTerm) ||
  article.content.toLowerCase().includes(searchTerm)
);

// Advanced search with filters
const advancedSearch = filter(articles, {
  title: { $contains: 'typescript' },
  category: { $in: ['Technology', 'Programming'] },
  status: 'published',
  publishDate: { $gte: new Date('2025-01-01') },
  views: { $gte: 1000 }
});

// Popular articles
const popularArticles = filter(articles, {
  views: { $gte: 10000 },
  likes: { $gte: 500 },
  status: 'published'
});

// Articles by tag
const taggedArticles = filter(articles, {
  tags: { $contains: 'tutorial' },
  status: 'published'
});

// Recent articles by author
const authorArticles = filter(articles, {
  author: { $startsWith: 'John' },
  publishDate: { $gte: new Date('2025-01-01') },
  status: 'published'
});

Inventory Management โ€‹

ts
interface InventoryItem {
  sku: string;
  name: string;
  quantity: number;
  reorderLevel: number;
  price: number;
  category: string;
  supplier: string;
  expiryDate: Date | null;
  location: string;
  tags: string[];
}

const inventory: InventoryItem[] = [/* ... */];

// Low stock alerts
const lowStock = filter(inventory, (item) =>
  item.quantity <= item.reorderLevel
);

// Items needing reorder
const needsReorder = filter(inventory, {
  quantity: { $lte: 10 },
  reorderLevel: { $gte: 10 }
});

// Expiring items (next 30 days)
const thirtyDaysFromNow = new Date();
thirtyDaysFromNow.setDate(thirtyDaysFromNow.getDate() + 30);

const expiringItems = filter(inventory, (item) =>
  item.expiryDate !== null &&
  item.expiryDate <= thirtyDaysFromNow &&
  item.quantity > 0
);

// High-value inventory
const highValueItems = filter(inventory, {
  price: { $gte: 1000 },
  quantity: { $gte: 1 }
});

const totalValue = highValueItems.reduce((sum, item) =>
  sum + (item.price * item.quantity), 0
);

// Items by supplier
const supplierItems = filter(inventory, {
  supplier: { $in: ['Supplier A', 'Supplier B'] },
  quantity: { $gt: 0 }
});

// Items by location and category
const warehouseElectronics = filter(inventory, {
  location: { $startsWith: 'Warehouse' },
  category: 'Electronics',
  quantity: { $gte: 1 }
});

Performance Optimization โ€‹

Tips and strategies for optimal performance.

When to Use Each Pattern โ€‹

Performance Ranking (fastest to slowest):

  1. Simple String/Number/Boolean - Fastest

    typescript
    filter(data, 'Berlin');  // โœ… Fastest
  2. Object-Based Filtering - Very Fast

    typescript
    filter(data, { city: 'Berlin' });  // โœ… Very Fast
  3. Operators - Fast (optimized with early exit)

    typescript
    filter(data, { age: { $gte: 18 } });  // โœ… Fast
  4. Wildcards - Moderate (regex compilation cached)

    typescript
    filter(data, '%berlin%');  // โš ๏ธ Moderate
  5. Predicate Functions - Slowest (most flexible)

    typescript
    filter(data, (item) => item.age > 18);  // โš ๏ธ Slowest

Caching Strategy โ€‹

typescript
const largeDataset = [/* ... */]; // 100,000 items

// โŒ Without cache: Re-computes every time
for (let i = 0; i < 1000; i++) {
  filter(largeDataset, { category: 'Electronics' });
}

// โœ… With cache: Computes once, reuses result
for (let i = 0; i < 1000; i++) {
  filter(largeDataset, { category: 'Electronics' }, { enableCache: true });
}

When to Enable Cache:

  • Large datasets (>1000 items)
  • Repeated identical queries
  • Read-heavy workloads
  • Static data

When NOT to Enable:

  • Frequently changing data
  • One-time queries
  • Memory-constrained environments

Large Dataset Handling โ€‹

typescript
// โŒ Slow: Processing entire dataset
const results = filter(millionRecords, complexExpression);
displayResults(results);

// โœ… Better: Pagination
const pageSize = 100;
const page = 0;
const pagedData = millionRecords.slice(page * pageSize, (page + 1) * pageSize);
const results = filter(pagedData, expression);

// โœ… Best: Pre-filter with operators, then apply complex logic
const preFiltered = filter(millionRecords, {
  category: { $in: ['Electronics', 'Books'] }  // Fast operator filter
});
const finalResults = filter(preFiltered, complexPredicate);  // Smaller dataset

Optimization Tips โ€‹

typescript
// โŒ Slow: Complex predicate on large dataset
filter(largeDataset, (item) => {
  const calculated = item.price * 1.2 + item.tax;
  return calculated > 100 &&
    item.category.toLowerCase().includes('electronics') &&
    item.inStock &&
    item.rating >= 4.0;
});

// โœ… Fast: Use operators when possible
filter(largeDataset, {
  price: { $gte: 80 },  // Pre-calculated threshold
  category: { $contains: 'electronics' },
  inStock: { $eq: true },
  rating: { $gte: 4.0 }
});

// โœ… Fast: Pre-filter with simple checks first
const preFiltered = filter(largeDataset, { inStock: true });
const results = filter(preFiltered, complexExpression);

Benchmarking โ€‹

typescript
// Measure filter performance
console.time('Filter Performance');
const results = filter(data, expression, options);
console.timeEnd('Filter Performance');

// Compare different approaches
const testData = Array.from({ length: 10000 }, (_, i) => ({
  id: i,
  value: Math.random() * 1000,
  category: i % 2 === 0 ? 'A' : 'B'
}));

console.time('Simple Object');
filter(testData, { category: 'A' });
console.timeEnd('Simple Object');

console.time('Operator');
filter(testData, { value: { $gte: 500 } });
console.timeEnd('Operator');

console.time('Predicate');
filter(testData, (item) => item.value >= 500);
console.timeEnd('Predicate');

Migration Guides โ€‹

Migrating to v5.0.0 โ€‹

From v3.x:

โœ… 100% Backward Compatible - No breaking changes!

All v3.x code continues to work:

typescript
// โœ… v3.x syntax still works in v5.0.0
filter(data, 'string');
filter(data, { prop: 'value' });
filter(data, (item) => true);
filter(data, '%pattern%');

New Features to Adopt:

typescript
// โœ… v5.0.0: MongoDB-style operators
filter(data, { age: { $gte: 18, $lt: 65 } });

// โœ… v5.0.0: Configuration options
filter(data, expression, {
  caseSensitive: true,
  maxDepth: 5,
  enableCache: true
});

// โœ… v5.0.0: Runtime validation
import { validateExpression, validateOptions } from '@mcabreradev/filter';

Recommended Updates:

typescript
// Before (v3.x) - Still works
filter(products, (p) => p.price >= 100 && p.price <= 500);

// After (v5.0.0) - Recommended
filter(products, {
  price: { $gte: 100, $lte: 500 }
});

// Benefits:
// - More declarative and readable
// - Can be serialized to JSON
// - Better TypeScript support
// - Runtime validation

From Native Array.filter() โ€‹

Direct Replacements:

typescript
// Native filter
const adults = users.filter(u => u.age >= 18);

// @mcabreradev/filter equivalent
const adults = filter(users, (u) => u.age >= 18);
// OR better with operators:
const adults = filter(users, { age: { $gte: 18 } });

// Native: Multiple conditions
const results = users.filter(u =>
  u.age >= 18 &&
  u.city === 'Berlin' &&
  u.isActive
);

// @mcabreradev/filter
const results = filter(users, {
  age: { $gte: 18 },
  city: 'Berlin',
  isActive: true
});

Enhanced Capabilities:

typescript
// โŒ Native: No wildcard support
const results = users.filter(u =>
  u.email.includes('gmail.com')
);

// โœ… @mcabreradev/filter
const results = filter(users, {
  email: { $endsWith: 'gmail.com' }
});
// OR
const results = filter(users, '%gmail.com');

// โŒ Native: Complex string operations
const results = users.filter(u =>
  u.name.toLowerCase().startsWith('al')
);

// โœ… @mcabreradev/filter
const results = filter(users, {
  name: { $startsWith: 'Al' }
});

When to Migrate:

Migrate When:

  • Need wildcard pattern matching
  • Filtering by partial object matches
  • Want to serialize filter expressions
  • Need case-insensitive search
  • Want MongoDB-style query syntax
  • Need deep object comparison

Keep Native When:

  • Simple one-time predicates
  • Performance is ultra-critical (native is marginally faster)
  • No dependencies requirement is strict
  • Project already has comprehensive native filter logic

Validation & Error Handling โ€‹

Runtime validation with Zod.

Expression Validation โ€‹

typescript
import { validateExpression } from '@mcabreradev/filter';

// Valid expressions
validateExpression('string');          // โœ… Valid
validateExpression(42);                // โœ… Valid
validateExpression({ prop: 'value' }); // โœ… Valid
validateExpression((x) => true);       // โœ… Valid

// Invalid expressions
try {
  validateExpression(undefined);       // โŒ Throws error
} catch (error) {
  console.error(error.message);
  // "Invalid filter expression: Expected string | number | boolean | null | function | object"
}

try {
  validateExpression(Symbol('test')); // โŒ Throws error
} catch (error) {
  console.error(error.message);
}

Options Validation โ€‹

typescript
import { validateOptions } from '@mcabreradev/filter';

// Valid options
validateOptions({ caseSensitive: true });  // โœ… Valid
validateOptions({ maxDepth: 5 });          // โœ… Valid
validateOptions({ enableCache: false });   // โœ… Valid
validateOptions({});                       // โœ… Valid (uses defaults)

// Invalid options
try {
  validateOptions({ maxDepth: 15 });      // โŒ maxDepth must be 1-10
} catch (error) {
  console.error(error.message);
  // "Invalid filter options: maxDepth too large"
}

try {
  validateOptions({ caseSensitive: 'yes' }); // โŒ Wrong type
} catch (error) {
  console.error(error.message);
  // "Invalid filter options: Expected boolean, received string"
}

Common Errors & Solutions โ€‹

Error: "Invalid filter expression" โ€‹

typescript
// โŒ Problem
filter(data, undefined);
filter(data, null);

// โœ… Solution
if (expression !== undefined && expression !== null) {
  filter(data, expression);
}

Error: "Invalid filter options: maxDepth too large" โ€‹

typescript
// โŒ Problem
filter(data, expression, { maxDepth: 15 });

// โœ… Solution
filter(data, expression, { maxDepth: 10 }); // Max is 10

Error: Unexpected Results โ€‹

typescript
// โŒ Problem: Case sensitivity issue
filter(users, 'BERLIN', { caseSensitive: true });
// Returns [] if all data is lowercase

// โœ… Solution: Check case sensitivity
filter(users, 'berlin', { caseSensitive: false }); // Default

Debug Tips โ€‹

typescript
// 1. Validate before filtering
import { validateExpression, validateOptions } from '@mcabreradev/filter';

try {
  validateExpression(expression);
  validateOptions(options);
  const results = filter(data, expression, options);
} catch (error) {
  console.error('Filter error:', error.message);
}

// 2. Test with simple data first
const testData = [{ id: 1, name: 'Test' }];
const testResult = filter(testData, expression);
console.log('Test result:', testResult);

// 3. Check expression type
console.log('Expression type:', typeof expression);
console.log('Expression value:', expression);

// 4. Verify data structure
console.log('Data sample:', data[0]);
console.log('Data length:', data.length);

API Reference โ€‹

Complete reference for all exported functions and types.

filter<T>(array, expression, options?) โ€‹

Main filtering function.

Signature:

typescript
function filter<T>(
  array: T[],
  expression: Expression<T>,
  options?: FilterOptions
): T[]

Parameters:

  • array (T[]): Array to filter
  • expression (Expression\<T>): Filter expression (string, number, boolean, null, object, or predicate)
  • options (FilterOptions, optional): Configuration options

Returns: T[] - Filtered array

Throws: Error if expression or options are invalid

Examples:

typescript
filter([1, 2, 3], 2);
filter(users, { age: 30 });
filter(products, { price: { $gte: 100 } });
filter(items, (item) => item.active);

validateExpression(expression) โ€‹

Validates a filter expression.

Signature:

typescript
function validateExpression<T>(expression: unknown): Expression<T>

Parameters:

  • expression (unknown): Expression to validate

Returns: Expression\<T> - Validated expression

Throws: Error if expression is invalid

Examples:

typescript
validateExpression('string');    // โœ… Returns 'string'
validateExpression(undefined);   // โŒ Throws Error

validateOptions(options) โ€‹

Validates filter options.

Signature:

typescript
function validateOptions(options: unknown): FilterOptions

Parameters:

  • options (unknown): Options to validate

Returns: FilterOptions - Validated options

Throws: Error if options are invalid

Examples:

typescript
validateOptions({ caseSensitive: true });  // โœ… Returns options
validateOptions({ maxDepth: 15 });         // โŒ Throws Error (max is 10)

mergeConfig(options) โ€‹

Merges options with defaults.

Signature:

typescript
function mergeConfig(options?: FilterOptions): FilterConfig

Parameters:

  • options (FilterOptions, optional): User options

Returns: FilterConfig - Complete configuration with defaults

Examples:

typescript
mergeConfig();  // Returns default config
mergeConfig({ caseSensitive: true });  // Merges with defaults

createFilterConfig(options) โ€‹

Creates a complete filter configuration.

Signature:

typescript
function createFilterConfig(options?: FilterOptions): FilterConfig

Parameters:

  • options (FilterOptions, optional): User options

Returns: FilterConfig - Complete configuration

Examples:

typescript
const config = createFilterConfig({ maxDepth: 5 });

Type Exports โ€‹

typescript
// Expression types
export type Expression<T> =
  | PrimitiveExpression
  | PredicateFunction<T>
  | ObjectExpression<T>
  | ExtendedObjectExpression<T>;

export type PrimitiveExpression = string | number | boolean | null;

export type PredicateFunction<T> = (item: T) => boolean;

export type ObjectExpression<T> = Partial<{
  [K in keyof T]: T[K] | string;
}>;

// Config types
export interface FilterConfig {
  caseSensitive: boolean;
  maxDepth: number;
  customComparator?: Comparator;
  enableCache: boolean;
}

export type FilterOptions = Partial<FilterConfig>;

export type Comparator = (actual: unknown, expected: unknown) => boolean;

// Operator types
export interface ComparisonOperators {
  $gt?: number | Date;
  $gte?: number | Date;
  $lt?: number | Date;
  $lte?: number | Date;
  $eq?: unknown;
  $ne?: unknown;
}

export interface ArrayOperators {
  $in?: unknown[];
  $nin?: unknown[];
  $contains?: unknown;
  $size?: number;
}

export interface StringOperators {
  $startsWith?: string;
  $endsWith?: string;
  $contains?: string;
}

Testing Your Filters โ€‹

Best practices for testing filter logic.

Unit Testing with Vitest/Jest โ€‹

typescript
import { describe, it, expect } from 'vitest'; // or 'jest'
import { filter } from '@mcabreradev/filter';

describe('User Filtering', () => {
  const users = [
    { id: 1, name: 'Alice', age: 30, role: 'admin' },
    { id: 2, name: 'Bob', age: 25, role: 'user' },
    { id: 3, name: 'Charlie', age: 35, role: 'user' }
  ];

  it('filters by age', () => {
    const result = filter(users, { age: { $gte: 30 } });
    expect(result).toHaveLength(2);
    expect(result[0].name).toBe('Alice');
    expect(result[1].name).toBe('Charlie');
  });

  it('filters by role', () => {
    const result = filter(users, { role: 'admin' });
    expect(result).toHaveLength(1);
    expect(result[0].name).toBe('Alice');
  });

  it('handles empty results', () => {
    const result = filter(users, { age: { $gt: 100 } });
    expect(result).toEqual([]);
  });

  it('filters with predicates', () => {
    const result = filter(users, (u) => u.age > 28);
    expect(result).toHaveLength(2);
  });
});

Mocking Data โ€‹

typescript
// Test helpers
function createMockUser(overrides = {}) {
  return {
    id: 1,
    name: 'Test User',
    age: 25,
    email: 'test@example.com',
    isActive: true,
    ...overrides
  };
}

describe('Complex Filters', () => {
  it('handles large datasets', () => {
    const largeDataset = Array.from({ length: 1000 }, (_, i) =>
      createMockUser({ id: i, age: 20 + (i % 50) })
    );

    const result = filter(largeDataset, { age: { $gte: 30, $lt: 40 } });
    expect(result.length).toBeGreaterThan(0);
  });
});

Edge Cases โ€‹

typescript
describe('Edge Cases', () => {
  it('handles empty arrays', () => {
    const result = filter([], { id: 1 });
    expect(result).toEqual([]);
  });

  it('handles null values', () => {
    const data = [
      { id: 1, value: null },
      { id: 2, value: 'test' }
    ];
    const result = filter(data, { value: null });
    expect(result).toHaveLength(1);
  });

  it('handles undefined properties', () => {
    const data = [
      { id: 1 },
      { id: 2, value: 'test' }
    ];
    const result = filter(data, { value: 'test' });
    expect(result).toHaveLength(1);
  });

  it('handles special characters', () => {
    const data = [
      { email: 'user@example.com' },
      { email: 'admin@test.org' }
    ];
    const result = filter(data, { email: '%@example.com' });
    expect(result).toHaveLength(1);
  });
});

Integration Testing โ€‹

typescript
describe('E-commerce Integration', () => {
  let products;

  beforeEach(() => {
    products = loadTestProducts(); // Load test data
  });

  it('filters products for product listing page', () => {
    const results = filter(products, {
      category: 'Electronics',
      price: { $lte: 1000 },
      inStock: true,
      rating: { $gte: 4.0 }
    });

    expect(results.length).toBeGreaterThan(0);
    results.forEach(product => {
      expect(product.category).toBe('Electronics');
      expect(product.price).toBeLessThanOrEqual(1000);
      expect(product.inStock).toBe(true);
      expect(product.rating).toBeGreaterThanOrEqual(4.0);
    });
  });
});

Frequently Asked Questions โ€‹

How do I filter by multiple conditions with OR logic? โ€‹

Use separate filter calls or predicates:

typescript
// Option 1: Separate filters and combine
const electronics = filter(products, { category: 'Electronics' });
const books = filter(products, { category: 'Books' });
const result = [...electronics, ...books];

// Option 2: Use $in operator
const result = filter(products, {
  category: { $in: ['Electronics', 'Books'] }
});

// Option 3: Predicate function
const result = filter(products, (p) =>
  p.category === 'Electronics' || p.category === 'Books'
);

Can I filter nested arrays? โ€‹

Use predicate functions:

typescript
const data = [
  { id: 1, items: [{ name: 'A' }, { name: 'B' }] },
  { id: 2, items: [{ name: 'C' }] }
];

const result = filter(data, (item) =>
  item.items.some(subItem => subItem.name === 'A')
);

How do I handle null/undefined values? โ€‹

typescript
const data = [
  { id: 1, value: null },
  { id: 2, value: undefined },
  { id: 3, value: 'test' }
];

// Filter for null
filter(data, { value: null });  // Returns id: 1

// Filter out null/undefined
filter(data, (item) => item.value != null);  // Returns id: 3

What's the performance impact of operators vs predicates? โ€‹

Operators are generally faster due to optimizations:

typescript
// โœ… Faster: Operators with early exit
filter(data, { age: { $gte: 18 } });

// โš ๏ธ Slower: Predicate (more flexible but slower)
filter(data, (item) => item.age >= 18);

// For best performance: Use operators when possible

Can I use this in React/Vue/Angular? โ€‹

Yes! Works in any JavaScript/TypeScript environment:

typescript
// React
const FilteredList = () => {
  const [products, setProducts] = useState([/* ... */]);
  const [priceFilter, setPriceFilter] = useState(100);

  const filtered = filter(products, {
    price: { $lte: priceFilter }
  });

  return <div>{filtered.map(p => <div key={p.id}>{p.name}</div>)}</div>;
};

// Vue
export default {
  computed: {
    filteredProducts() {
      return filter(this.products, {
        category: this.selectedCategory
      });
    }
  }
};

How do I debug complex filters? โ€‹

typescript
// 1. Break down the filter
const step1 = filter(data, { category: 'Electronics' });
console.log('After category filter:', step1.length);

const step2 = filter(step1, { price: { $lte: 1000 } });
console.log('After price filter:', step2.length);

// 2. Test expression validity
import { validateExpression } from '@mcabreradev/filter';
validateExpression(myExpression);

// 3. Log results
const result = filter(data, expression);
console.log('Results:', result.length, result);

Can operators be serialized to JSON? โ€‹

Yes! This is a major advantage:

typescript
// Save filter to JSON
const filterExpr = {
  price: { $gte: 100, $lte: 500 },
  category: { $in: ['Electronics', 'Books'] }
};
localStorage.setItem('savedFilter', JSON.stringify(filterExpr));

// Load and use later
const loaded = JSON.parse(localStorage.getItem('savedFilter'));
const results = filter(products, loaded);

How do I filter by date ranges? โ€‹

typescript
const startDate = new Date('2025-01-01');
const endDate = new Date('2025-12-31');

const results = filter(orders, {
  date: {
    $gte: startDate,
    $lte: endDate
  }
});

// Last 30 days
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

const recent = filter(orders, {
  date: { $gte: thirtyDaysAgo }
});

Can I chain multiple filter calls? โ€‹

Yes:

typescript
const result = filter(
  filter(
    filter(data, { category: 'Electronics' }),
    { price: { $lte: 1000 } }
  ),
  { inStock: true }
);

// Or better: Combine in one call
const result = filter(data, {
  category: 'Electronics',
  price: { $lte: 1000 },
  inStock: true
});

How do I filter case-sensitive strings? โ€‹

typescript
// Case-insensitive (default)
filter(users, 'alice');  // Matches 'Alice', 'ALICE', 'alice'

// Case-sensitive
filter(users, 'alice', { caseSensitive: true });  // Only 'alice'

// With operators
filter(users, {
  name: { $startsWith: 'Al' }
}, { caseSensitive: true });

Troubleshooting โ€‹

"Invalid filter expression" error โ€‹

Problem: Passing invalid expression types

typescript
// โŒ These cause errors
filter(data, undefined);
filter(data, Symbol('test'));
filter(data, new Map());

Solution:

typescript
// โœ… Valid expressions only
if (expression !== undefined && expression !== null) {
  filter(data, expression);
}

// โœ… Validate first
import { validateExpression } from '@mcabreradev/filter';
try {
  validateExpression(expression);
  filter(data, expression);
} catch (error) {
  console.error('Invalid expression:', error.message);
}

TypeScript type errors โ€‹

Problem: Type mismatches

typescript
interface Product {
  id: number;
  name: string;
}

// โŒ Error: 'invalidProp' does not exist
filter<Product>(products, { invalidProp: 'value' });

// โŒ Error: Type 'string' not assignable
filter<Product>(products, { id: 'not-a-number' });

Solution:

typescript
// โœ… Use correct types
filter<Product>(products, { id: 1 });
filter<Product>(products, { name: 'test' });

// โœ… Use type assertions carefully
filter(products, { someField: 'value' } as any);

Unexpected results with wildcards โ€‹

Problem: Wildcard not matching

typescript
// โŒ No results
filter(users, '%Alice%');  // Expecting matches but gets []

Solution:

typescript
// Check case sensitivity
filter(users, '%Alice%', { caseSensitive: false });  // Default

// Check actual data
console.log('Sample data:', users[0]);

// Try simpler pattern
filter(users, 'Alice');  // Without wildcards

Performance issues โ€‹

Problem: Slow filtering on large datasets

typescript
// โš ๏ธ Slow: Complex predicate on 100k items
filter(largeDataset, (item) => {
  // Complex calculations
  return complexCondition(item);
});

Solution:

typescript
// โœ… Use operators
filter(largeDataset, {
  price: { $gte: 100 },
  category: { $in: ['A', 'B'] }
});

// โœ… Enable cache for repeated queries
filter(largeDataset, expression, { enableCache: true });

// โœ… Pre-filter with simple conditions
const preFiltered = filter(largeDataset, { inStock: true });
const final = filter(preFiltered, complexExpression);

Cache not working โ€‹

Problem: Cache doesn't seem to improve performance

Checklist:

  1. โœ… Enable cache: { enableCache: true }
  2. โœ… Use identical expressions (objects must be same reference or identical)
  3. โœ… Data hasn't changed between calls
  4. โœ… Filtering same dataset

Operators not detected โ€‹

Problem: Operators treated as regular values

typescript
// โŒ Might be treated as literal object
const expr = { price: { $gt: 100 } };
filter(products, expr);  // Not working

Solution:

typescript
// โœ… Ensure correct syntax
filter(products, {
  price: { $gt: 100 }  // Inline or properly structured
});

// โœ… Check TypeScript types
import type { ComparisonOperators } from '@mcabreradev/filter';
const priceFilter: ComparisonOperators = { $gt: 100 };
filter(products, { price: priceFilter });

Contributing & Support โ€‹

Contributing โ€‹

We welcome contributions! Please see the contributing guidelines for details.

How to Contribute:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes with tests
  4. Submit a pull request

Areas for Contribution:

  • Bug fixes
  • Documentation improvements
  • Performance optimizations
  • New operator ideas
  • Example use cases

Reporting Bugs โ€‹

Please open an issue on GitHub with:

  • Clear description of the bug
  • Minimal reproduction example
  • Expected vs actual behavior
  • Environment details (Node.js version, TypeScript version)

Feature Requests โ€‹

We love hearing your ideas! Open an issue with:

  • Use case description
  • Proposed API (if applicable)
  • Why existing features don't solve it

Support โ€‹

  • GitHub Issues: Bug reports and feature requests
  • GitHub Discussions: Questions and community support
  • Documentation: This wiki and README
  • Examples: Check examples/ directory

Version Support Policy โ€‹

  • v3.x: No longer supported

Version History โ€‹

v5.2.4 (Latest - October 2025) โ€‹

Major Features:

  • ๐Ÿค– Intelligent Autocomplete - Type-aware operator suggestions
  • ๐Ÿ—๏ธ Nested Object Autocomplete - 4-level deep autocomplete support
  • ๐Ÿ“ Regex Operators - $regex and $match for pattern matching
  • ๐Ÿ”€ Logical Operators - $and, $or, $not for complex queries
  • ๐Ÿ’จ Lazy Evaluation - filterLazy, filterFirst for efficient processing
  • ๐Ÿš€ Enhanced Caching - Multi-layer memoization (530x faster)
  • ๐Ÿ“ฆ 18 Total Operators - Complete MongoDB-style operator suite

Operator Count:

  • Comparison: 6 operators ($gt, $gte, $lt, $lte, $eq, $ne)
  • Array: 4 operators ($in, $nin, $contains, $size)
  • String: 5 operators ($startsWith, $endsWith, $contains, $regex, $match)
  • Logical: 3 operators ($and, $or, $not)
  • Total: 18 operators

Performance Improvements:

  • 530x faster with result caching
  • 500x faster with lazy evaluation for early exits
  • 80x less memory usage with filterLazy
  • Optimized regex pattern caching

Breaking Changes:

  • None (100% backward compatible)

Improvements:

  • Better TypeScript inference for nested objects
  • Improved performance with lazy evaluation
  • Enhanced documentation with all features
  • Real-world examples for all operators
  • 463+ comprehensive tests

Released under the MIT License.