13

I want to map an object type to a subtype that includes only keys whose values are of a specific type.

For example, something like ExtractNumeric<T>, where ExtractNumeric<{ str: string, num: number }> should be equivalent to the type: { num: number }

I've tried this, but it does not work:

type ExtractNumeric<T> = { [k in keyof T]: T[k] extends number ? T[k] : never }

This snippet throws a type error: let obj: ExtractNumeric<{ str: string, num: number }> = { num: 1 }

Because although the str key expects a value of never, the compiler complains about its absence.

prmph
  • 7,616
  • 11
  • 37
  • 46

1 Answers1

18

Linked aticle in the comment, but in a nutshell:

type SubType<Base, Condition> = Pick<Base, {
    [Key in keyof Base]: Base[Key] extends Condition ? Key : never
}[keyof Base]>;

type ExtractNumeric<T> = SubType<T, number>

vittore
  • 17,449
  • 6
  • 44
  • 82
  • This mostly works, but consider this: `let obj: SubType<{ str: string, num: number }, boolean> = { num: 1, str: "" }` It does not produce an error, but I guess that is more due to TypeScripts quirks about empty object types – prmph Jun 03 '19 at 16:42
  • 1
    As of TypeScript 4.1, there's an easier way to do this by re-mapping keys: https://stackoverflow.com/a/63990350 – chocolateboy Mar 01 '21 at 07:17