TypeScript as a Team Contract
In 2020 I sold TypeScript as documentation you get for free. Since then I've migrated a large codebase to zero type errors. Types are a contract between people as much as between functions, but only if the build enforces them.
On this page
My 2020 post on TypeScript made three claims: types are documentation that lives with the code, they make onboarding easier because a new collaborator can see what every function expects, and you can adopt them gradually without converting a codebase in one go.
All three hold up. What I didn’t understand then is the condition that makes them true.
Types only help if they’re enforced
A few years later at Sky I worked on a large React codebase that had been “migrated” to TypeScript. The files were
.tsx, but the compiler reported a long backlog of errors, so type checking was switched off in the build. Nobody could
tell a new error from the old noise, and the types had quietly stopped meaning anything.
I took it to zero through months of small, non-functional merge requests, then turned type checking on in the build so a type error failed the pipeline (Driving a TypeScript Codebase to Zero Errors). That’s when the 2020 claims came true: the types became trustworthy documentation, reviewers stopped arguing about things the compiler could settle, and new code got real feedback.
The lesson: gradual adoption is only safe if you ratchet. Every cleaned area should get enforcement, and lint rules should stop new errors creeping back in.
A contract between people
The idea I’d add to the 2020 post is that types are a contract between people. A function signature tells the next developer what they may rely on. An API response type tells the front end what the back end has promised. When those types are generated from an API specification, they become a contract the two teams can check automatically (API Modelling).
Where it gets weak is at the boundaries. A type says what you expect the server to send; it doesn’t check what actually arrives. For data from outside your process, I now validate at runtime (a schema library) and derive the static type from the same schema, so the two can’t drift.
Habits that keep types honest
- No blanket
any. Useunknownand narrow it. If you must cast, make it searchable and leave a reason. - Prefer unions to enums.
as constobjects and string unions erase cleanly and read well. - Type the edges first. API responses and shared helpers are where one fix clears fifty errors.
- Strict mode for new code, even if old code isn’t there yet.
- Let types shape the design. If something is hard to type, it’s often hard to understand.
And with AI in the loop
Strong types are also one of the best feedback sensors for coding agents. An agent that runs tsc can correct its own
mistakes before a human reviews them. The stricter the types, the less steering it needs, which is exactly the
feedback-loop thinking in TDD as a Feedback Loop.
Originally written in 2020 → TypeScript
- #typescript
- #type-safety
- #code-quality
- #documentation
- #migration
↩ Linked from (1)
…orrect and consistent across every client. That's the same instinct behind API Modelling and typed contracts (TypeScript as a Team Contract): make the server's promises explicit, then let the UI rely on them.
↪ Links to (3)
Related by topic
- Growingcase study
A Testing Strategy Teams Actually Adopted
Frontend craft - Evergreen
Preventing XSS in React
Frontend craft - Evergreen
React Testing Strategy
Frontend craft - Growing
AG Grid Performance Patterns
Real-time UIs