filter-obj
Filter object keys and values into a new object using a predicate function or a list of keys.
Repository Health
Technical Analysis
filter-obj is a minimal, dependency-free utility for building a new object that includes or excludes a chosen subset of another object’s own properties. It exposes two functions — includeKeys and excludeKeys — each accepting either a predicate function that receives the key, value, and source object, or a plain array/Set of keys to keep or drop.
Unlike a naive Object.keys().reduce() implementation, filter-obj preserves property descriptors (getters, setters, enumerability) via Object.getOwnPropertyDescriptor/defineProperty and correctly retains symbol-keyed properties through Reflect.ownKeys(), making it a safer drop-in for object filtering than hand-rolled alternatives.
What You Get
- includeKeys(object, predicate) for building a new object from properties that match a predicate function
- excludeKeys(object, predicate) for the inverse — drop properties matching a predicate
- Support for passing an array or Set of keys directly instead of a predicate function
- Correct handling of property descriptors, symbol keys, and non-enumerable/inherited properties
- Full TypeScript types with distributive Pick/Omit semantics for the key-list overloads
Common Use Cases
- Stripping internal or sensitive fields (e.g. password, tokens) before sending an object to an API response or log
- Picking a whitelist of fields from a large config or options object
- Building request/response DTOs by including only allowed keys from an entity object
- Cleaning up query-string or form-data objects by excluding empty/falsy values via a predicate
Under The Hood
Architecture The entire library lives in a single index.js file with no internal layering: includeKeys is the primitive, iterating either a supplied array/Set of keys or the full Reflect.ownKeys(object) result and copying matching properties across via Object.getOwnPropertyDescriptor/defineProperty; excludeKeys is implemented purely as the complement, either negating a predicate or converting a key list to a Set and delegating back into includeKeys. This keeps the two public functions in lockstep — a fix to descriptor handling or symbol-key iteration in includeKeys automatically applies to excludeKeys with no duplicated logic.
Tech Stack
The package ships as ESM-only ("type": "module") with a package.json exports map pointing to index.js and index.d.ts, targets Node.js >=18, and has zero runtime dependencies. Its only devDependencies are ava (test runner), xo (ESLint-based linter/style enforcer), and tsd (type-definition test runner) — there is no build/bundle step since the raw ESM source is published directly.
Code Quality
test.js contains an extensive ava suite covering both functions across predicate, array, and Set argument forms, plus edge cases like symbol-keyed properties, non-enumerable properties, inherited prototype properties, getter/setter descriptor preservation, and __proto__ handling. index.test-d.ts exercises the type overloads with tsd. npm test runs xo (lint), ava (tests), and tsd (type tests) together, and GitHub Actions CI runs this matrix across Node 18 and 20 on every push and pull request — a comprehensive quality bar for a library of this size.
API Design
The unified signature — a single function accepting either a predicate (key, value, object) => boolean or a plain array/Set of keys — merges what libraries like Lodash split into separate pick/pickBy/omit/omitBy functions into two functions total, reducing the API surface while keeping both dynamic and static filtering ergonomic. Documentation is limited to the README’s inline examples with no separate docs site or example directory, so newcomers rely on the readme and TypeScript signatures to discover behavior.