I am trying to create a generic type that can retrieve the type of a specific key from a potentially nested object type. It will receive the object, and the key as generics. The path to that key isn't known though, so it potentially needs to iterate over each value to find it. Here is what I've come up with so far.
type GetDeepProp<T extends object, Key extends string> = Key extends keyof T
? T[Key]
: {
[k in keyof T]: T[k] extends object
? GetDeepProp<T[k], Key>
: unknown
}[keyof T]
//examples
type ShallowUser = { region: string; }
type DeepUser = { account: { region: number; } }
type DeeperUser = { account: { location: { region: "USA" | "Canada" | "France", } } }
let shallowRegion: GetDeepProp<ShallowUser, 'region'> // should return string
let deepRegion: GetDeepProp<DeepUser, 'region'> //should return number
let deeperRegion: GetDeepProp<DeeperUser, 'region'> //should return "USA" | "Canada"
After poking at this for a while, I've found this solution that actually seems to work. But I don't understand why it works. Should not this very last line [keyof T] create create a union of all the types from all the keys, and not just the key passed in? I guess my question is, why does this work (or maybe it doesn't hold up), and is there a better way to accomplish this?