Filtering Object Properties in TypeScript

If you use TypeScript, you’ve more than likely seen keyof typeof obj at one point or another to get a union type representing the keys of the given object. But what if we want to get a subset of the object keys, based on the values in the object?

We can do this by creating a Filter type which will take two generic arguments: the object type and the type of values to keep.

type Filter<Obj, ValueType> = {
  [K in keyof Obj]: Obj[K] extends ValueType ? K : never
}

A real-world use case for this might be a maxBy function that we can pass an array of objects and a key which we want to find the max value of. We can use Filter<T, number> to only allow keys which are numeric values since no other data type makes sense for this use case.

export function maxBy<
  T extends Record<string, unknown>,
  K extends Filter<T, number>[keyof T],
>(collection: T[], by: K): number {
  return collection.reduce(
    (acc, item) => Math.max(item[by] as number, acc),
    0,
  )
}