I get the following typescript error:
const myFunction = (
param1: string | undefined,
param2: { someProp: string } | undefined
) => {
if (!param1 && !param2) {
return;
}
// Here I get the following Typescript error:
// (parameter) param2: { someProp: string } | undefined
// Object is possibly 'undefined'.ts(2532)
const param3 = param1 ? param1 : param2.someProp;
};
the following works:
const param4 = param1 ? param1 : param2 ? param2.someProp : null;
but seems redundant to check for null or undefined twice.
I have to mention that the strictNullChecks
option is set to true
in the compilerOptions and want to keep it like this.
Any idea why I get this error?
Here's a CodeSandbox with the code: https://codesandbox.io/s/jn2mp01q2v
The sad truth about the TypeScript compiler is that it just isn't as smart as a human being (as of TypeScript 3.4 anyway) and so its control flow analysis is but a pale shadow of the sort of analysis you can perform yourself. Of course, it is very consistent about its analysis, whereas mine tends to get worse when I haven't eaten recently.
If you perform a check on a variable of a union type which completely eliminates one or more of the constituents of that union, the compiler will happily narrow the type of the variable for you:
param1.charAt(0); // error, possibly undefined
if (!param1) return;
param1.charAt(0); // okay now
But one thing the compiler just doesn't do is keep track of correlated variables outside of discriminated unions. What you've eliminated by checking
if (!param1 && !param2) return;
is the possibility that both param1
and param2
can be undefined
at the same time. You've taken two previously independent variables, and made them correlated to each other. Which the compiler doesn't keep track of. Since param1
and param2
can both still be undefined
(just not at the same time), the compiler treats them as still independent and you are left with your problem.
You can do what the other answer suggested and use a type assertion, which is meant for occasions where you're smarter than the compiler and don't want to try to lead the compiler through the task of understanding what you already know:
const param3 = param1 ? param1 : param2!.someProp; // I'm smarter than the compiler 🤓
Note that I've used the non-null assertion operator !
which is probably the most concise way possible to assert your superiority over the machine. Also beware that such assertions are not safe, since you might be mistaken about your superiority. So only do something like this after you double and triple check that there is no way for param2
to be undefined
.
Another thing you can do is restructure your code so as to lead the compiler through an analysis that it can do.
const param3 = param1 || (param2 ? param2.someProp : undefined);
if (!param3) return;
param3.charAt(0); // string
This will work for you and you are only checking each parameter once. The variable param3
is of type string | undefined
, and is only undefined
if both param1
and param2
are falsy. Each step in that code completely eliminates union constituents for each variable, without leaving any correlated types lying around to confuse the compiler.
Either solution should work for you. Hope that helps; good luck!