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!