An interface with every field optional describes what a response might contain and lets the compiler agree that a success field exists on an error.
// what it usually looks like: everything optional, nothing checked
interface Result { ok?: boolean; data?: Order; error?: string; }
// a discriminated union: the compiler narrows on the tag
type Result =
| { status: 'ok'; data: Order }
| { status: 'error'; code: string; message: string };
if (res.status === 'ok') {
res.data.total; // known to exist
} else {
res.code; // and data is not accessible here
}
The narrowing is what makes this worth the extra syntax: after the check, the compiler knows which branch it is in and refuses the fields that do not belong. It also makes an exhaustive switch checkable — assigning the value to never in the default case is a compile error when a new variant is added and unhandled. This is the single highest-value TypeScript pattern for anything consuming an API.