TypeScript `readonly` Arrays and Tuples: When Immutability Saves You and When It Fights You TypeScript's readonly modifier for arrays and tuples only prevents mutation at the surface level, leaving nested objects mutable, which can create a false sense of security. Developers must understand the distinction between shallow and deep immutability, and use patterns like as const or DeepReadonly where appropriate. The choice between readonly syntaxes (readonly T[] vs ReadonlyArray) is ergonomic, but both enforce the same compile-time restrictions. readonly Arrays and Tuples: When Immutability Saves You and When It Fights You This article was written with the assistance of AI, under human supervision and review. Most readonly bugs stem from misunderstanding what the type actually prevents. Developers mark an array readonly , ship it to production, and discover that nested objects still mutate freely—or that function parameters reject their readonly values entirely. The failure mode here is subtle but expensive: you get type safety where you don't need it and vulnerability where you do. The problem isn't that readonly is broken. The problem is that teams treat it as a deep immutability guarantee when TypeScript enforces it only at the surface. This creates a false sense of security that explodes during code review or, worse, at runtime. The correct pattern requires understanding three layers: what readonly actually protects, where type widening sabotages you, and when deep immutability patterns justify their cost. Apply these correctly and your type system catches mutation bugs before deployment. Skip them and you're debugging object reference issues in production. readonly modifier prevents reassignment and mutation methods on arrays and tuples, but only at the first level—nested objects remain mutable unless explicitly typed. ReadonlyArray