I'm trying to find a type for generic error handling that does something like this:
function request(): GenericError<{body:string}> {
if (/* Some condition */) {
return { error: "An error occurred" };
}
return { body: "Things went well" };
}
The goal is to infer that body
exists if error
doesn't, i.e:
const response = request();
if (response.error) return;
/* TypeScript should infer that body can't be undefined here */
I don't know if this is possible in TypeScript and this question might be a duplicate, but I don't know how to word the problem exactly. I tried annotating the function with the answers in this question but none of them could guarantee body
to exist if error
didn't, as far as I could see.
CodePudding user response:
A union { error: string } | { body: string }
narrowing will do it :
function request(): { error: string } | { body: string } {
if (/* Some condition */) {
return { error: "An error occurred" };
}
return { body: "Things went well" };
}
const response = request();
if ('error' in response) { // narrowing
response.error // OK
return
}
response.body // OK
CodePudding user response:
I like to use this pattern than uses a discriminated union alongside a "success" property:
interface SuccessResult {
result: true;
body: string;
}
interface FailureResult {
result: false;
error: string;
}
type Result = SuccessResult | FailureResult;
Now change the original function to return this instead:
function request(): Result {
if (/* Some condition */) {
return { result: false, error: "An error occurred" };
}
return { result: true, body: "Things went well" };
}
And finally check for the outcome in the caller:
const response = request();
if (response.result) {
//Read response.body here, with response.error being invalid (won't compile)
} else {
//Read response.error here, with response.body being invalid (won't compile)
}