Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested keyof object paths (using dot notation) [duplicate]

Tags:

typescript

I'm looking for nested object paths: Is something like this possible?

interface IHuman {
    age: number;
    friend: {
        name: string;
    }
}

keyof IHuman; // "age", "friend.name"
like image 406
kraftwer1 Avatar asked Jul 31 '17 12:07

kraftwer1


3 Answers

type AnyObject = Record<string, any>

type DotJoin<A extends string, B extends string> = A extends '' ? B : `${A}.${B}`

type DeepKeys<O extends AnyObject> = {
  [K in keyof O]: O[K] extends AnyObject ? K : never
}[keyof O]

// @ts-expect-error Type 'keyof O' does not satisfy the constraint 'string'.
type DotBranch<O extends AnyObject, P extends string = '', K extends string = keyof O> =
  K extends DeepKeys<O>
  ? DotBranch<O[K], DotJoin<P, K>>
  : /*************/ DotJoin<P, K>
interface Obj {
  a: {
    x: string
    y: {
      z: string
    }
  }
  b: {
    u: boolean
  }
  c: number
}

type D = DotBranch<Obj> // type D = "c" | "a.x" | "a.y.z" | "b.u"

declare function get(path: DotBranch<Obj>)
get('') // Argument of type '""' is not assignable to parameter of type '"c" | "a.x" | "a.y.z" | "b.u"'.

Typescript Playground
GitHub Gist

like image 53
Qwerty Avatar answered Nov 02 '22 22:11

Qwerty


I don't think this is possible, as for why i can make a wild guess:

interface IHuman {
    age: number;
    'friend.name': any;
    friend: {
        name: string;
    }
}

const b: keyof IHuman = 'friend.name';

friend.name would now be ambigious.

like image 39
Tom Cumming Avatar answered Nov 03 '22 00:11

Tom Cumming


I've not found a nice solution for this too. But you might want to take a look at typed-path project.

The main idea of this project in a single image

like image 1
ramlez Avatar answered Nov 02 '22 23:11

ramlez