Home > Blockchain >  Is it possible to annotate exclusive union in TypeScript?
Is it possible to annotate exclusive union in TypeScript?

Time:08-24

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.


Typescript Playground

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 

Playground

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)
}
  • Related