Why does typescript think I have an Error when it can only be null?

159 views Asked by At

I have this situation where Typescript is not behaving how I expect (n.b. I can't switch on strictNullChecks for the whole project):

const error = new Error("I'm and error");
const textError = "Also and error";

const printErrorMessage = (err: string | Error) => {
  const errorMessage = (err === null || typeof err === "string") ? err : err?.message ?? err?.name ?? 'unknown error';
  if (errorMessage) {
    console.log(errorMessage);
  }
  return errorMessage;
}

const errorMessageOne = printErrorMessage(error);
const errorMessageTwo = printErrorMessage(textError);
const errorMessageThree = printErrorMessage(null);

My hope was that the only time that err is returned as itself is if it's null or a string, but that means the return value should either be Null or string not string | Error.

screenshot of the TS playground, with a tooltip showing the return type is string 'or' Error

Because this function can be sent a null object, but I don't want to convert that to the string 'unknown error' I can't just let null slide through.

Here's my TS playground where I've confirm this happens outside of my dev environment.

3

There are 3 answers

0
AncientSwordRage On BEST ANSWER

After posting my question and playing around some more I found a temporary solution (not recommended, but I need a stop gap for the time being).

You can change the assignment line to have a cast (not recommended!) to get around this: const errorMessage = (err === null || typeof err === "string") ? (err as null | string) : err?.message ?? err?.name ?? 'unknown error';

Definitely follow the other answers if you're able to do so.

3
Uroš Anđelić On

Edit: the answer from @T.J. Crowder is correct.

My answer:

If you want to be able to pass null to the printErrorMessage function, you should accept null in the function signature:

const printErrorMessage = (err: string | Error | null) => { ... }

The inferred return type will then be string | null.

2
T.J. Crowder On

You need to enable strictNullChecks (I suggest enabling all of the strict options via "strict": true). The playground you've shared doesn't have it, and that's why the return type is string | Error. If you enable it, you'll get string | null as you expect.