A discriminated union, not a bag of optional fields
A Result with data? and error? lets the impossible state through: 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 with data, and the compiler tells you when you forgot the other branch. Every state machine in your code wants this.
typescript