The Case for Type Safety
I used to think type safety was a nice-to-have. Then I spent a month debugging a production incident caused by a string being passed where a number was expected — the database silently coerced it, the aggregation returned NaN, and a dashboard showed $NaN to a customer.
TypeScript with strict mode catches most of these at compile time. But compile-time types are a lie — they don't exist at runtime. That's where runtime validation comes in.
We use Zod to define schemas that serve double duty: TypeScript types at compile time and runtime validators at the boundary. Every API request, every database read, every message from the queue gets validated against its schema. If the shape doesn't match, we log the discrepancy and reject the data.
The result? Data quality issues dropped by 90%. The remaining 10% are caught by monitoring before they reach a user. The compile-time errors catch refactoring mistakes. The runtime errors catch integration bugs. Together, they form a net that catches almost everything.
The investment is front-loaded — writing schemas takes time. But every hour spent on type safety saves ten hours of debugging. I've never met a team that regretted going strict.