The codebase has 100% TypeScript coverage. Every function is typed. Every API response is typed. The types are carefully maintained. The codebase is also completely unmaintainable — circular dependencies everywhere, business logic scattered across utility files with no coherent ownership, components that know about the database schema, and a God object that half the application imports directly.
TypeScript did not cause this. TypeScript also did not prevent it. TypeScript was not designed to. That is the part the community has been unclear about.
What TypeScript Actually Does
TypeScript moves a category of bugs from runtime to compile time. That is genuinely valuable. Passing the wrong type to a function, accessing a property that may not exist, calling a method on null — these are real bugs and TypeScript prevents them. In a large team with many developers touching the same code, the type system is a communication mechanism that scales. You know what a function expects without reading its implementation. That is a real benefit.
What TypeScript does not do: enforce separation of concerns, prevent business logic from living in the wrong layer, detect when a module has grown to 2,000 lines because nobody wanted to refactor it, or tell you that your API layer is calling functions that belong in your domain layer. Architecture is about boundaries and ownership. Types are about shapes. These are completely different problems.
“A perfectly typed mess is still a mess. The compiler is happy. The engineer maintaining it in eighteen months is not.”
The Substitution Fallacy
Teams that adopted TypeScript often treated it as a substitute for architectural discipline. "We have TypeScript, so the codebase is under control." The types create a visible artefact of correctness that feels like the same thing as a well-designed system. It is not. A strict TypeScript config passing cleanly is a necessary condition for a maintainable codebase, not a sufficient one. The bar was already low. TypeScript just reliably clears it.
The same fallacy applies to linting, formatting, and test coverage. All of these are valuable. None of them make architectural decisions. A codebase can pass every static check you can run on it and still be something that takes a new engineer six months to understand well enough to be useful in.
What Architecture Actually Requires
Architecture requires humans making deliberate decisions about where things live and why. Which layer handles HTTP concerns and which handles domain logic. Where state lives and who can mutate it. What a module is allowed to import and what it cannot. These decisions do not emerge from a type system. They come from engineers who have seen what happens when they are not made, and who care enough to make them even when the deadline is tomorrow.
TypeScript is a tool. It is a good tool. It solves a real problem. It does not solve the problem of engineers building systems without thinking about how they will grow. That problem requires a different tool: time, review, and the willingness to say "this was the wrong shape, let us change it before we build more on top of it."

