6

My question is similar to Types from both keys and values of object in Typescript, but with an additional layer of nesting:

interface Outer {
  a: {
    b: number
  },
  c: {
    d: string
  }
}

And I'm only looking to retrieve the union type of all values, here number | string.

Here's my stab:

type Values<T extends Record<string, any>> = T[keyof T]; // From previous SO answer

type InnerValues<
  T extends Record<string, Record<string, any>>,
  K extends keyof T
> = T[K][keyof T[K]];

type All = Values<Outer>;
type In = InnerValues<Outer, keyof Outer>; // expected number|string

but I have an error saying Outer doesn't have an index type.

Playground link.

1 Answer 1

9

T[K][keyof T[K]] will not work because T[K] will be a union of all possible values in T (well the values specified by K anyway) and keyof T[K] will probably end up being never if the values have no common keys.

The solution is to take each constituent in the union T[K] and get its possible values. We can do this using a distributive conditional type

interface Outer {
  a: {
    b: number;
  };
  c: {
    d: string;
  };
}

type DistributiveValues<T extends Record<string, any>> = T extends T ? T[keyof T] : never;

type InnerValues<
  T extends Record<keyof T, object>,
  K extends keyof T
> = DistributiveValues<T[K]>;

type In = InnerValues<Outer, keyof Outer>; // is number|string

play

Sign up to request clarification or add additional context in comments.

1 Comment

Would it be possible to make this recursive so it could give you a union of all the non-Record leaf value types in an arbitrarily deep nesting of objects? For example, if the property d in Outer was an object rather than a string.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.