Implement recursive DeepReadonly<T> for nested objects and arrays
Tests recursive mapped types and conditional type narrowing. A strong answer uses a conditional to split arrays into ReadonlyArray, objects into readonly mapped types, and leaves primitives untouched.
WHAT THIS TESTS: This question probes your ability to manipulate TypeScript's type system at the structural level. It specifically checks whether you understand recursive conditional types, mapped types with the readonly modifier, and the subtle differences between arrays, objects, and primitives in type-space. Interviewers want to see that you can build utility types that preserve semantics across nested structures rather than applying shallow transformations.
A GOOD ANSWER COVERS: A strong implementation starts with a conditional type that branches three ways. First, if T extends an array type like Array<infer U>, it returns ReadonlyArray<DeepReadonly<U>> so that array methods and the readonly modifier are preserved correctly. Second, if T extends object, it must first exclude null because null extends object in TypeScript's type system; for non-null objects it returns a mapped type with readonly keys where each property value is wrapped in DeepReadonly. Third, for everything else, primitives and special values like functions, it returns T unchanged to stop recursion. The candidate should mention that the readonly modifier is placed before the mapped index signature to freeze properties.
COMMON WRONG ANSWERS: The biggest red flag is skipping the array branch and letting arrays fall into the object branch. Mapping over keyof an array produces an object type with numeric keys and strips away array methods like push and pop, which destroys the array semantics. Another frequent mistake is forgetting that null extends object, which causes the type to try mapping over null and producing broken output. Some candidates also omit the readonly modifier in the mapped type, producing a DeepReadonly that is not actually readonly, or they fail to recurse on property values, leaving nested objects mutable.
LIKELY FOLLOW-UPS: The interviewer may ask how you would handle tuples versus arrays, which requires checking for readonly arrays or using tuple-specific inference. They might ask about Dates, RegExps, or functions, and whether DeepReadonly should freeze them or bail out via a more sophisticated check like T extends Function ? T. Another common follow-up is performance: deeply recursive types can hit TypeScript's recursion depth limit on very nested structures, so the candidate should know about tail recursion or type instantiation depth limits.
ONE CONCRETE EXAMPLE: Consider a type User with a nested posts array. A shallow Readonly<User> would make the posts property readonly, but you could still push new items into posts and mutate individual post titles. With DeepReadonly, posts becomes a ReadonlyArray where both the array itself and every nested post object are frozen, so posts[0].title = "new" becomes a compile-time error.
Read the original → typescriptlang.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.