DEV Community

Cover image for TypeScript Utility: keyof nested object

TypeScript Utility: keyof nested object

Pedro Figueiredo on December 15, 2021

In this blog post, we will learn how to build a TypeScript util type, that exposes all the key paths of an object, including the nested ones. ...
Collapse
 
abetoots profile image
abe caymo

hi! can't thank you enough for this awesome post. still new to TS but how do I use this util for a function that returns an object which contains all keys generated from <NestedKeyOf> with values as string ?

Collapse
 
pffigueiredo profile image
Pedro Figueiredo

Hey Abe, thanks a lot for the feedback ;)

Could you try to provide me an example of what you are trying to achieve? Maybe using ts playground - you just need to edit and share the link after ;)

Collapse
 
abetoots profile image
abe caymo

so it's basically like this:

const useStyles = exposeStyles({
  merge: {
    root: "Checkbox",
    li: "Checkbox__li",
  },
  replace: {
    input: "Checkbox__input",
    description: "Checkbox__description",
  },
});

const classes = useStyles(props.classes);
Enter fullscreen mode Exit fullscreen mode

exposeStyles accepts an object where I define which keys are mergeable/replaceable. it returns a function which, when invoked, should return an object containing all those keys, like so: classes.root . I just don't know how to type that returned function

Thread Thread
 
pffigueiredo profile image
Pedro Figueiredo

I'm not 100% sure if you want to use NestedKeyOf in this scenario, and neither I'm sure of a few implementation details of your example. But take a look at this example that I started, and try to play around with it a bit, if you don't get it right, send me message over Twitter and I will help you further ;)

Collapse
 
krixpello profile image
KriXPello • Edited

To hide Array methods use this:

type NestedKey<O extends Record<string, unknown>> = {
[K in Extract<keyof O, string>]: O[K] extends Array<any>
? K
: O[K] extends Record<string, unknown>
? `${K}` | `${K}.${NestedKey<O[K]>}`
: K
}[Extract<keyof O, string>];

Collapse
 
pffigueiredo profile image
Pedro Figueiredo

Yap, there are multiple ways to hide an array, if I was aiming into that, something similar to this would probably be my bet, thanks ❤️

Collapse
 
somu93 profile image
somu93

${Key}.${NestedKeyOf<ObjectType[Key]>}. this line gives me an error when typescript version is 4.6.4 & 4.7.4 (latest) ->

Type instantiation is excessively deep and possibly infinite. Can you explain why and can you please also add the return type.

Collapse
 
kemotx90 profile image
kemotx90

use

`${Key}.${NestedKeyOf<ObjectType[Key]> extends infer U extends string ? U : never}`
Enter fullscreen mode Exit fullscreen mode

instead of

${Key}.${NestedKeyOf<ObjectType[Key]>}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
skmohammadi profile image
skmohammadi

Your suggestion fixed the following TS error:

Type instantiation is excessively deep and possibly infinite.
Enter fullscreen mode Exit fullscreen mode
Collapse
 
jsonz1993 profile image
Jsonz

cool

Collapse
 
angeloryndon profile image
Angelo Ryndon

Thank you! will definitely use this helper at work :D

Collapse
 
codriniftimie profile image
Codrin Iftimie

If anyone is looking for a solution that works with objects that include arrays, which would make this article complete, I stumbled upon this localcoder.org/typescript-deep-key...

In here there is a brief mention of this file used in react-hook-form.

This is the version I ended up using. This also includes methods of getting the type of the key which would come in handy

Collapse
 
pabloimrik17 profile image
Pablo F. Guerra

Hi @codriniftimie, any chance you could update your type for array with this syntax?

Instead of a.b.1 --> a.b.[1]

I would help me a lot in my current project.

Collapse
 
dzey profile image
Jakub Królak

I found this solution that I think is simpler and easier to understand

type NestedKeyOf<T, K = keyof T> = K extends keyof T & (string | number)
  ? `${K}` | (T[K] extends object ? `${K}.${NestedKeyOf<T[K]>}` : never)
  : never
Enter fullscreen mode Exit fullscreen mode
Collapse
 
akib profile image
Shuaib hasan akib • Edited

Genius!