A discriminated union, not a bag of optional fields
A Result with data? and error? lets impossible states through, with both set or neither. A union with a tag makes each shape complete.
type Result<T> =
| { ok: true; data: T }
| { ok: false; error: string };Now if (r.ok) narrows to the shape that has data, and the compiler tells you when you've forgotten the other branch. Every state machine in your code wants this.
typescript