# TypeScript taught me to design before I ship

For a long time, I treated TypeScript as “JavaScript with extra steps.” I added types where the editor complained, used any when I was in a hurry, and saw the type system as a formality rather than a tool.

TypeScript changed that view.

TypeScript’s type system is not just about catching typos. It lets you describe the shape of your application: what a user looks like, which fields can be null, what a successful API response contains, and what states a feature can be in. When you write User | null, Promise, or a discriminated union such as Loading | Success | Error, you are documenting intent directly in the code.

The real shift happens when you stop asking, “What type should I put here?” and start asking, “What are all the possible states of this data?” A function that returns string is much less useful than one that returns a clear result type. An object with optional fields is much safer when you decide whether undefined is allowed, and where it must be handled.

TypeScript also makes refactoring far less frightening. Rename a field, change a function signature, or remove a property, and the compiler shows every place affected. It cannot prove your business logic is correct, but it can prevent a whole category of mistakes before the code reaches production: missing fields, wrong argument types, forgotten null checks, and inconsistent API contracts.

The lesson I carry into every language is simple: make invalid states hard to represent. If a value can be absent, say so. If an operation can fail, model the failure. If an object has mutually exclusive states, use a union instead of hoping every developer remembers the rules.

TypeScript will not replace good architecture, tests, or careful thinking. But it gives you a fast, persistent reviewer that asks useful questions while you are still writing the code.
