The current shape keeps all three fields on one object:
{ ok: false, value: undefined, error: e }
value is present on the error case — just undefined. That's a nullable. You've moved the problem, not removed it.
A discriminated union has two distinct shapes:
{ ok: true, value: v } // no error field
{ ok: false, error: e } // no value field
TypeScript narrows this automatically on ok. After if (!result.ok) return result, the compiler knows result.value is V — not V | undefined. No
assertion, no cast, no optional chaining.
The single-object shape loses that. result.value is always typed as V | undefined regardless of what you've checked.
Reference: github.com/dmvjs/proposal-try-expression
The current shape keeps all three fields on one object:
{ ok: false, value: undefined, error: e }
value is present on the error case — just undefined. That's a nullable. You've moved the problem, not removed it.
A discriminated union has two distinct shapes:
{ ok: true, value: v } // no error field
{ ok: false, error: e } // no value field
TypeScript narrows this automatically on ok. After if (!result.ok) return result, the compiler knows result.value is V — not V | undefined. No
assertion, no cast, no optional chaining.
The single-object shape loses that. result.value is always typed as V | undefined regardless of what you've checked.
Reference: github.com/dmvjs/proposal-try-expression