filterObject
EditKeeps the own enumerable properties that satisfy a predicate.
/** Converts TypeScript numeric keys to the strings received at runtime. */export type FilterObjectKey<T extends object> = Extract<keyof T, PropertyKey> extends infer Key ? Key extends number ? number extends Key ? string : `${Key}` : Key : never;
const readDescriptorValue = ( descriptor: PropertyDescriptor, receiver: object): unknown => { if (Object.hasOwn(descriptor, "value")) return descriptor.value; return descriptor.get ? Reflect.apply(descriptor.get, receiver, []) : undefined;};
/** Keeps the own enumerable properties that satisfy a predicate. */export const filterObject = <T extends object>( object: T extends readonly unknown[] ? never : T, predicate: ( this: void, value: T[keyof T], key: FilterObjectKey<T>, object: T ) => boolean): Partial<T> => { if (Array.isArray(object)) { throw new TypeError("object must not be an array"); } const filtered = Object.create(null) as Partial<T>;
const properties = Reflect.ownKeys(object).flatMap((key) => { const descriptor = Reflect.getOwnPropertyDescriptor(object, key); return descriptor ? [{ key, descriptor }] : []; }); const entries = properties .filter(({ descriptor }) => descriptor.enumerable) .map(({ key, descriptor }) => ({ key, value: readDescriptorValue(descriptor, object) as T[keyof T], }));
for (const { key, value } of entries) { if (predicate(value, key as FilterObjectKey<T>, object)) { Object.defineProperty(filtered, key, { value, enumerable: true, configurable: true, writable: true, }); } }
return filtered;};Download
Section titled “Download”wget -O src/lib/filterObject.ts https://raw.githubusercontent.com/jrTilak/lazykit/HEAD/registry/functions/filterObject.tstemp_dir="$(mktemp -d)" && bunx degit jrTilak/lazykit/registry/functions "$temp_dir" && mv "$temp_dir/filterObject.ts" src/lib/filterObject.ts && rm -r "$temp_dir"Examples
Section titled “Examples”import { filterObject } from "./filterObject";
const user = { name: "Charlie", age: 28, active: true, role: "editor" };const textFields = filterObject(user, (value) => typeof value === "string");
console.log(textFields);// { name: "Charlie", role: "editor" }object(T) — Non-array object whose own enumerable properties should be tested.predicate((value, key, object) => boolean) — Returnstruefor properties to retain and is invoked without a receiver. Numeric TypeScript keys arrive as their runtime string form.
Returns
Section titled “Returns”Partial<T> — A null-prototype object containing the matching string and symbol
properties, so inherited names cannot appear as unprocessed values.
Arrays are rejected with TypeError because the result is a plain object.
Special keys such as __proto__ are copied as safe own data properties.