Annotated solution
Published September 4, 2026The solution
type DeepPartial<T> = { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K] }
The common wrong answer
type DeepPartial<T> = { [K in keyof T]?: T[K] }
That is `Partial`, and it stops at the first level. `{ a: { b: string } }` becomes `{ a?: { b: string } }` — the outer key is optional, and `b` is still as required as it ever was. Depth does not come for free; the type has to ask for it.
Line by line
T[K] extends object ? DeepPartial<T[K]> : T[K]The recursion lives in the value clause. Anything object-shaped goes back through `DeepPartial`; primitives are returned untouched, which is what terminates the descent.
[K in keyof T]?:The `?` is applied at every level because every level is a fresh call to the same mapped type. One rule, written once, applied all the way down.
Takeaway
A recursive mapped type is just a mapped type that calls itself in the value position. The condition that stops it — here, "is this still an object?" — matters more than the recursion itself.
