Rule 14 of 38 · Chapter II — Design for Change
Make illegal states unrepresentable
Why this rule exists
If your types allow a nonsensical combination of values, someone will eventually produce it, and every function downstream has to defend against a state that should never exist. Encoding the rules in the type system deletes whole categories of bug before runtime: the illegal state simply cannot be constructed, so it cannot be handled wrong.
In practice
Model with types that only permit valid combinations. Replace a bag of nullable fields with a union of the states that actually occur, so a loading value cannot also carry an error. Use non-empty lists, tagged variants, and narrow types at the boundary so the core receives only well-formed data and stops re-checking it.
Example
type State = {
loading: boolean;
data?: Result;
error?: Error;
}; // loading + error?type State =
| { tag: 'loading' }
| { tag: 'ok'; data: Result }
| { tag: 'err'; error: Error };When it doesn't apply
Weakly typed languages limit how far you can push this; there, validate at the edge and trust inward. And do not contort a model into knots for an impossible case that a simple assertion would cover more clearly.