Mapped type for deep transformations in Typescript - Time & Space Complexity
When using mapped types to transform all properties deeply in TypeScript, it's important to understand how the work grows as the input type gets bigger.
We want to know how the time to create the transformed type changes when the input has more nested properties.
Analyze the time complexity of the following code snippet.
type DeepReadonly = {
readonly [K in keyof T]: T[K] extends object ? DeepReadonly : T[K];
};
interface Example {
a: number;
b: { c: string; d: boolean };
}
type ReadonlyExample = DeepReadonly;
This code defines a mapped type that makes all properties deeply readonly, including nested objects.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursively visiting each property in the object type.
- How many times: Once for each property at every nesting level.
As the input type has more properties and deeper nesting, the number of operations grows with every property visited.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 properties, 1 level | 10 |
| 10 properties, 2 levels | About 20 (10 + 10 nested) |
| 10 properties, 3 levels | About 30 (10 + 10 + 10 nested) |
Pattern observation: The work grows roughly in proportion to the total number of properties across all levels.
Time Complexity: O(n)
This means the time to transform grows linearly with the total number of properties in the input type, including nested ones.
[X] Wrong: "The transformation only runs once regardless of nesting depth."
[OK] Correct: Because the mapped type recurses into each nested object, it must process every nested property, so deeper nesting means more work.
Understanding how recursive mapped types scale helps you reason about type transformations and their impact on compile-time performance, a useful skill for writing efficient TypeScript code.
"What if we changed the mapped type to only transform properties at the top level, skipping nested objects? How would the time complexity change?"