Question presented to candidate:
"Partial<T> only makes the top level optional. How would you build a DeepPartial<T> that makes every nested property optional β and what would you watch out for?"
What a strong answer should cover:
- The basic idea: a mapped type with
?that recurses into object-typed properties - Why the one-liner
T[K] extends object ? DeepPartial<T[K]> : T[K]breaks:X | nullis not distributed so it is not recursed into, andDates and functions turn into bags of optional members ({}is accepted, functions stop being callable) - A robust version: leaf types (primitives,
Date,RegExp, functions) pass through, a nakedTdistributes over unions, arrays and tuples keep their shape,MapandSethandled explicitly - Typical use: config overrides and test fixtures, merged into defaults by a deep-merge function whose behaviour matches the type (arrays replace,
undefinedkeeps the default) - Caveats: explicit
undefinedis allowed under plainstrict(exactOptionalPropertyTypeschanges that), and inside generic codeDeepPartial<T>stays unresolved
Clarifying questions expected:
- Should arrays become partial element by element, or be replaced as a whole?
- Which types are leaves for this codebase (dates, class instances, branded types)?
Code / implementation expected: Yes β write DeepPartial<T>, show where the naive version fails, and use it in a typed merge.