Annotated solution
Published August 4, 2026The solution
type MyReadonly<T> = { readonly [K in keyof T]: T[K] }
The common wrong answer
type MyReadonly<T> = { [K in keyof T]: Readonly<T[K]> }
This applies `Readonly` to each *value* instead of to the mapping. For a primitive like `string` that does nothing at all, so the keys stay mutable and the result is just a copy of `T`.
Line by line
readonly [K in keyof T]The modifier precedes the key clause, mirroring how you would write `readonly host: string` in an interface. It marks the property, not the type of its value.
T[K]The value passes through untouched, which is what keeps this shallow. Recursing here instead is exactly how `DeepReadonly` is built.
Takeaway
Modifiers act on properties; wrapping the value type is a different operation entirely. Confusing the two produces a type that looks right and enforces nothing.