Search code examples
typescripttypescript-generics

How can I infer the key used for indexed access type?


I want to create a helper type to infer the key used inside an indexed access type.

Example:

type X = { foo: string, bar: boolean }
type Fn = <T extends X>(value: T) => T["foo"]
type Helper<T> = ???

type Result = Helper<Fn> // should be "foo"

The approach I tried is similar to the built-in ReturnType helper, but doesn't work so far:

type Helper<Fn> = Fn extends (value: infer T) => infer R
  // R extends T[infer Key] does not work: Type 'Key' cannot be used to index type 'T'.
  ? R extends T[keyof T]
    ? T[keyof T]
    : never
  : never

Is this even possible?


Solution

  • You can achieve something reasonably close using a mapped type, but this requires you to know what T is beforehand:

    type Helper<T, Fn extends (...args: any[]) => any> = {
        [K in keyof T]: T[K] extends ReturnType<Fn> ? K : never;
    }[keyof T];
    
    type Result = Helper<X, Fn>;
    //   ^? "foo"
    

    However, a major drawback is that if X has multiple keys with the same type,

    type X = { foo: string; bar: boolean; baz: string };
    

    then the result will include all of those keys:

    type Result = Helper<X, Fn>;
    //   ^? "foo" | "baz"
    

    Playground