npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@filter-def/in-memory

v0.2.0

Published

In-memory filtering for filter-def

Downloads

165

Readme

@filter-def/in-memory

In-memory filtering adapter for filter-def. Define type-safe filters once, get predicates that work with native array methods.

Installation

npm install @filter-def/in-memory
# or
pnpm add @filter-def/in-memory

Quick Start

import { inMemoryFilter } from "@filter-def/in-memory";
import type { InMemoryFilterInput } from "@filter-def/in-memory";

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

const userFilter = inMemoryFilter<User>().def({
    name: { kind: "eq" },
    emailContains: { kind: "contains", field: "email" },
    olderThan: { kind: "gt", field: "age" },
});

// Create a predicate function
const predicate = userFilter({
    name: "John",
    emailContains: "@example.com",
    olderThan: 25,
});

// Use with native array methods
const users: User[] = [
    /* ... */
];
const filteredUsers = users.filter(predicate);
const firstUser = users.find(predicate);
const hasMatch = users.some(predicate);

Features

  • Type-safe filters: Full TypeScript inference for filter inputs and entity fields
  • Composable: Combine multiple filters with AND/OR logic
  • Native integration: Returns predicates for filter(), find(), some(), every()
  • Custom filters: Define complex business logic with custom filter functions
  • Zero dependencies: Lightweight and framework-agnostic (only depends on @filter-def/core)

API

inMemoryFilter<Entity>()

Creates a filter builder for the specified entity type.

const productFilter = inMemoryFilter<Product>().def({
    // Filter definitions...
});

makeFilterHelpers(filter)

Creates convenience wrapper functions around native array methods.

import { inMemoryFilter, makeFilterHelpers } from "@filter-def/in-memory";

const userFilter = inMemoryFilter<User>().def({
    name: { kind: "eq" },
    isActive: { kind: "eq" },
});

const {
    filter: filterUsers,
    find: findUser,
    findIndex: findUserIndex,
    some: someUsers,
    every: everyUser,
} = makeFilterHelpers(userFilter);

const activeUsers = filterUsers(users, { isActive: true });
const john = findUser(users, { name: "John" });

Filter Types

Primitive Filters

| Kind | Description | Input Type | | ----------- | --------------------------- | -------------- | | eq | Exact equality match | Field type | | neq | Not equal | Field type | | contains | String contains substring | string | | inArray | Value is in provided array | Field type[] | | gt | Greater than | Field type | | gte | Greater than or equal | Field type | | lt | Less than | Field type | | lte | Less than or equal | Field type | | isNull | Check if null/undefined | boolean | | isNotNull | Check if not null/undefined | boolean |

Field Inference

When the filter name matches an entity field, the field property is inferred:

const filter = inMemoryFilter<User>().def({
    name: { kind: "eq" }, // field: "name" inferred
    email: { kind: "contains" }, // field: "email" inferred
    olderThan: { kind: "gt", field: "age" }, // explicit field required
});

Boolean Filters (AND/OR)

Combine conditions with logical operators. All conditions must have explicit field properties.

const filter = inMemoryFilter<User>().def({
    // OR: match any condition
    searchTerm: {
        kind: "or",
        conditions: [
            { kind: "contains", field: "name" },
            { kind: "contains", field: "email" },
        ],
    },

    // AND: match all conditions
    priceRange: {
        kind: "and",
        conditions: [
            { kind: "gte", field: "price" },
            { kind: "lte", field: "price" },
        ],
    },
});

Custom Filters

Define custom logic for complex filtering scenarios:

interface BlogPost {
    tags: string[];
    publishedAt: Date;
    viewCount: number;
    likeCount: number;
}

const postFilter = inMemoryFilter<BlogPost>().def({
    // Check if post has a specific tag
    hasTag: (post, tag: string) => post.tags.includes(tag),

    // Check if published within X days
    publishedWithinDays: (post, days: number) => {
        const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
        return post.publishedAt >= cutoff;
    },

    // Calculate engagement rate
    minEngagementRate: (post, minRate: number) => {
        return post.likeCount / post.viewCount >= minRate;
    },
});

const trending = posts.filter(
    postFilter({
        publishedWithinDays: 7,
        minEngagementRate: 0.1,
        hasTag: "featured",
    }),
);

Nested Filters

Filter parent entities based on child properties:

interface User {
    name: string;
    posts: Post[];
}

interface Post {
    id: string;
    title: string;
}

const postFilter = inMemoryFilter<Post>().def({
    id: { kind: "eq" },
    titleContains: { kind: "contains", field: "title" },
});

const userFilter = inMemoryFilter<User>().def({
    name: { kind: "eq" },
    wrotePostWithId: (user, postId: string) =>
        user.posts.some(postFilter({ id: postId })),
    hasPostWithTitle: (user, title: string) =>
        user.posts.some(postFilter({ titleContains: title })),
});

const authors = users.filter(userFilter({ hasPostWithTitle: "TypeScript" }));

Type Utilities

InMemoryFilterInput<T>

Extract the input type from a filter definition:

import type { InMemoryFilterInput } from "@filter-def/in-memory";

const userFilter = inMemoryFilter<User>().def({
    name: { kind: "eq" },
    minAge: { kind: "gte", field: "age" },
});

type UserFilterInput = InMemoryFilterInput<typeof userFilter>;
// { name?: string; minAge?: number }

InMemoryFilter<Entity, Input>

Type for the compiled filter function:

import type { InMemoryFilter } from "@filter-def/in-memory";

// The filter is a function that takes input and returns a predicate
type UserFilter = InMemoryFilter<User, { name?: string }>;
// (filterInput?: { name?: string }) => (entity: User) => boolean

InMemoryCustomFilter<Entity, Input>

Type for custom filter functions:

import type { InMemoryCustomFilter } from "@filter-def/in-memory";

// Custom filters take (entity, input) and return boolean
type HasTagFilter = InMemoryCustomFilter<BlogPost, string>;
// (entity: BlogPost, input: string) => boolean

Options

Case-Insensitive Contains

const filter = inMemoryFilter<User>().def({
    nameSearch: {
        kind: "contains",
        field: "name",
        caseInsensitive: true,
    },
});

Examples

See the examples directory for comprehensive usage examples:

Related Packages