Looks like a nice code interview question ;) This is possible using template literal types introduced already quite a while ago. Here is how:
type PickByDotNotation<TObject, TPath extends string> =
// If TKey has a dot, split it into two: the part before the dot and after the dot
TPath extends `${infer TKey}.${infer TRest}` ?
// Checking if the key actually exists in the object
TKey extends keyof TObject ?
// Get type recursively
PickByDotNotation<TObject[TKey], TRest> :
// Provided key is invalid
never :
// The path doesn't contain a dot, so just trying to use it as a key
TPath extends keyof TObject ?
TObject[TPath] :
never
Playground link
You can make the first clause a bit simpler using infer ... extends ...
introduced in TS 4.7
type PickByDotNotation<TObject, TPath extends string> =
// Constraining TKey so we don't need to check if its keyof TObject
TPath extends `${infer TKey extends keyof TObject & string}.${infer TRest}` ?
PickByDotNotation<TObject[TKey], TRest> :
TPath extends keyof TObject ?
TObject[TPath] :
never
Playground link
However I'd not recommend to use this type in actual code, at least I cannot guarantee that it will always work as you want it to. Particularly the template string part: I'm pretty sure if there are multiple dots in TPath
TS documentation never says if TKey
will be the part before the first dot or before the last one, or maybe even some random dot in the middle