This looks like a great question for a coding interview ;) You can achieve this using template literal types that were introduced quite a while ago. Here's how:
type ExtractByDotNotation<TObject, TPath extends string> =
// If TKey has a dot, split it into two parts: before the dot and after the dot
TPath extends `${infer TKey}.${infer TRest}` ?
// Checking if the key exists in the object
TKey extends keyof TObject ?
// Get type recursively
ExtractByDotNotation<TObject[TKey], TRest> :
// Key provided is invalid
never :
// If the path doesn't contain a dot, use it as a key
TPath extends keyof TObject ?
TObject[TPath] :
never
Playground link
You can simplify the first clause using infer ... extends ...
from TS 4.7
type ExtractByDotNotation<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}` ?
ExtractByDotNotation<TObject[TKey], TRest> :
TPath extends keyof TObject ?
TObject[TPath] :
never
Playground link
However, I wouldn't recommend using this type in production code, as there may be uncertainties in how the template string part behaves with multiple dots in TPath
. TS documentation doesn't specify if TKey
will be before the first dot, last dot, or somewhere random in between.