Revision:
To ensure you fully comprehend the implications of the solution provided, please review the issues raised by @jcalz in the comment section below.
If you decide to create your own recursive types, it's advisable to incorporate a mechanism, such as the iteration counter suggested by @Maciej Sikora (especially if your code will be part of a public library).
Solution
In cases involving recursive types, encountering this error is sometimes inevitable. However, there exists a solution:
type Paths<Obj> = Obj extends object
? {
[Key in keyof Obj]: Obj[Key] extends infer I ? Prepend<Paths<I>, Key> : never
// add this ^ ^
}[keyof Obj]
: [];
The use of infer
declaration defers type evaluation, preventing the issue of hitting the hard instantiation limit counter and subsequently avoiding the
Type instantiation is excessively deep
compile error. It is essential to thoroughly test the type after implementing this workaround, as disabling a compiler safety check introduces potential risks.
Alternatively, you can optimize the Paths
type manually or utilize a library like ts-toolbelt, which already includes a similar mechanism (discovered by the author @pirix-gh who uses this approach in their library).
Additional Resources