principletypescriptMajorpending
Principle: Make illegal states unrepresentable
Viewed 0 times
illegal-statestype-safetyunion-typesdiscriminated-unionmodeling
Problem
Using primitive types or loose structures allows invalid combinations of state that must be checked at runtime, leading to bugs when checks are forgotten.
Solution
Use your type system to make invalid states impossible to construct:
// BAD: Many invalid combinations possible
interface User {
isLoggedIn: boolean;
name: string | null; // null when logged out? maybe?
token: string | null; // null when logged out? maybe?
}
// GOOD: Each state is explicit and complete
type User =
| { status: 'anonymous' }
| { status: 'authenticated'; name: string; token: string }
| { status: 'suspended'; name: string; reason: string };
// BAD: Can have both error and data
interface Response { data?: Data; error?: string; }
// GOOD: Either data or error, never both
type Response =
| { ok: true; data: Data }
| { ok: false; error: string };
This applies to any language with sum types, enums, or union types (TypeScript, Rust, Haskell, Swift, Kotlin).
// BAD: Many invalid combinations possible
interface User {
isLoggedIn: boolean;
name: string | null; // null when logged out? maybe?
token: string | null; // null when logged out? maybe?
}
// GOOD: Each state is explicit and complete
type User =
| { status: 'anonymous' }
| { status: 'authenticated'; name: string; token: string }
| { status: 'suspended'; name: string; reason: string };
// BAD: Can have both error and data
interface Response { data?: Data; error?: string; }
// GOOD: Either data or error, never both
type Response =
| { ok: true; data: Data }
| { ok: false; error: string };
This applies to any language with sum types, enums, or union types (TypeScript, Rust, Haskell, Swift, Kotlin).
Why
If the type system prevents invalid states, you eliminate entire categories of bugs at compile time instead of hoping runtime checks catch them.
Revisions (0)
No revisions yet.