TypeScript: Everyday Types - discussion (2023-01-25)
The TS handbook's "Everyday Types" section is the baseline, but I'm curious what people consider the *highest ROI* types in route-first React apps: route contracts, intent objects, status lanes, and derived evidence keys. Where does typing actually make debugging easier, and where does it just add ceremony?
What do you type strictly (route keys, vault/doc shapes) vs leave flexible (API payloads, UI helpers)? Do you use discriminated unions for intent/actions, or keep it simpler? How do you avoid type drift when you store lots of derived keys and evidence strings?
Comments (14)
Back to latestStatus lanes as unions are the biggest payoff for us.
Once you stop juggling booleans, a bunch of impossible states disappear.
We type route keys and intent objects strictly, and we treat external payloads as unknown until validated.
Types are contracts; external data isn't a contract until you make it one.
Counterpoint: strict types can slow down migrations when the contract is still moving.
We sometimes relax types temporarily, but we keep the shared contract (route/vault) strict.
Same. I think the dividing line is who depends on it.
If other modules/routes depend on it, strict. If it's local and experimental, be pragmatic.
Typing evidence keys helped us more than I expected.
If you have data-* evidence surfaces, naming and typing keeps them consistent across the app.
We use discriminated unions for intents that get logged/replayed.
If it's going into a ledger or effects log, it should be typed like an API.
Avoiding drift: we centralize derived writes in one helper, and the helper is typed against the document/vault shape.
If derivation is scattered, you get both runtime drift and type drift.
The best ROI types in UI code are the boring ones: string unions for tabs/panels, and strict shapes for route defaults.
Once defaults are concrete, everything else can infer without fancy generics.
A misunderstanding I had: typing everything doesn't make the app correct.
It makes the *contracts* correct, which is still extremely valuable.
Typing derived keys prevents silent typos (totla vs total).
If you store derived state a lot, spelling becomes correctness.
Docs tie-in: typing feels like the same theme as the docs posture: make contracts explicit and behavior legible.
Related: API Reference and Testing and Debugging.
We also type the "lane" strings across systems (fetch lane, mutation lane, effect lane).
It made logs and screenshots consistent because the vocabulary is now enforced.
If your types are too fancy, they become a barrier to entry.
We aim for types that make code review easier, not types that show off.
Counterpoint: strict types can hide runtime issues if people trust the compiler too much.
We still store validation flags as derived keys because runtime truth matters.
The best TS advice I've heard: type the things that are contracts, not the things that are convenient to type.