3

Is it possible to extract type form object providing a path to it in N size tuple format. If so, how? Example what I have in mind:

type ExtractType<O, T> = ...;
type Foo = ExtractType<{ a: { b: number } }, ['a', 'b']> // I expect Foo type to be number

3 Answers 3

4

Below naive version, naive it means I don't restrict path to be valid path of the object, if keys path is invalid the return type will be unknown.

type ExtractType<O, T extends Array<any>> = {
  [K in keyof O]:
    ((...a: T) => any) extends ((a: any, ...args: infer Tail) => any)
 ? Tail['length'] extends 0 ? O[K] : ExtractType<O[K], Tail> : never
}[T[0]]

// example Foo is number
type Foo = ExtractType<{ a: { b: { c: {d: number} } }, g: string }, ['a', 'b', 'c', 'd']> 

It is recursive type so depth is not restricted. Few things to consider:

  • ((...a: T) => any) extends ((a: any, ...args: infer Tail) => any) this part is used in order to cut the Head of the tuple, and work recursively with Tail. It means we traverse the object until tuple with keys will be empty. Every recursive call work with one element less.
  • Tail['length'] extends 0 ? O[K] : ExtractType<O[K], Tail> - we take the value type only when we are in the end of the key tuple
Sign up to request clarification or add additional context in comments.

Comments

0

If you want to limit yourself to a depth of 2, so just a tuple as path, you can use the following type definition:

type ExtractType<
  O extends { [K1 in T[0]]: { [K2 in T[1]]: any } },
  T extends [string, string]
> = O[T[0]][T[1]];

type Foo = ExtractType<{ a: { b: number } }, ['a', 'b']> // number

Playground Link

1 Comment

I would want for this not to be limited if possible. But thanks for putting me on track.
0

Maciej Sikora's answer did not work for me. Changing the array for a string made it easier to recursively traverse in Typescript:

export type ExtractType<T, K extends string = string> =
  K extends `${infer KHead}.${infer KTail}`
  ? (KHead extends keyof T ? ExtractType<T[KHead], KTail> : never)
  : (K extends keyof T ? T[K] : never);

So you would call it:

ExtractType<{ a: { b: number } }, 'a.b'> // = number

Comments

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.