Skip to content

filterObject

Edit

Keeps the own enumerable properties that satisfy a predicate.

filterObject.ts
/** 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;
};
Terminal
wget -O src/lib/filterObject.ts https://raw.githubusercontent.com/jrTilak/lazykit/HEAD/registry/functions/filterObject.ts
filterObject.example.ts
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) — Returns true for properties to retain and is invoked without a receiver. Numeric TypeScript keys arrive as their runtime string form.

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.