Filtering an Object in TypeScript
Ever need to filter properties from an object? Here's how to do it.
In JavaScript:
function filterObject(obj, fn) {
return Object.fromEntries(Object.entries(obj).filter(fn));
}
It's a bit trickier in TypeScript:
type Entry<T> = {
[K in keyof T]: [K, T[K]];
}[keyof T];
function filterObject<T extends object>(
obj: T,
fn: (entry: Entry<T>, i: number, arr: Entry<T>[]) => boolean,
) {
return Object.fromEntries(
(Object.entries(obj) as Entry<T>[]).filter(fn),
) as Partial<T>;
}
In either case, we can use our filterObject
helper to return a new copy of an object with certain keys removed. Our filter function works just like Array.filter
, except that its callback function's first parameter will be the property's key value pair as array ([key, value]
).
const author = { name: "Steve", age: 93, height: 241 };
const onlySteves = filterObject(author, ([k, v]) => v === "Steve");
// { name: "Steve" }
const onlyNumbers = filterObject(author, ([k, v]) => typeof v === "number");
// { age: 93, height: 241 }
const onlyNames = filterObject(author, ([k, v]) => k === "name");
// { name: "Steve" }
Older Browsers
If you wanted to do this by hand (or perhaps in older browsers without polyfills for Object.fromEntries
and Object.entries
), you could also do it this way: create a shallow copy of the object, iterate once to generating the entries, and then iterate again to delete
filtered properties.
function filterObject2<T extends object>(
obj: T,
fn: (entry: Entry<T>, i: number, arr: Entry<T>[]) => boolean,
): Partial<T> {
const next = { ...obj };
const entries: Entry<T>[] = [];
for (const key in obj) {
entries.push([key, obj[key]]);
}
for (let i = 0; i < entries.length; i++) {
const entry = entries[i];
if (!fn(entry, i, entries)) {
delete next[entry[0]];
}
}
return next;
}
Enjoy!