Reputation: 19764
I created a type guard which checks if the argument is exactly null
:
function isNotNull<T> (arg: T): arg is Exclude<T, null> {
return arg !== null
}
When I test it, the then
-branch works correctly: it strips away the null
from the type.
const value: string | null = 0 as any
if (isNotNull(value)) {
// value is of type `string` here
}
However, it becomes never
in the else
-branch.
const value: string | null = 0 as any
if (isNotNull(value)) {
// `value` is of type `string` here
} else {
// `value` is of type `never` here
}
I'd like it to resolve to null
in the else
-branch.
How can I achieve this?
Upvotes: 4
Views: 7879
Reputation: 95732
The problem here is the assignment:
const value: string | null = 0 as any
The compiler knows that value
is a constant, so it can never be null.
It doesn't get much better if you use let
:
let value: string | null = 'foo';
if (isNotNull(value)) {
// `value` is of type `string` here
} else {
// `value` is of type `never` here
}
Again the typescript compiler knows that the value is not null.
But if assign something where Typescript can't infer a constant value then you will have your expected string
in the if
branch and null
in the else
:
function isNotNull<T> (arg: T): arg is Exclude<T, null> {
return arg !== null
}
let value: string | null = foo();
if (isNotNull(value)) {
// `value` is of type `string` here
} else {
// `value` is of type `null` here
}
function foo(): string | null {
return "foo"
}
Also, even this last example only works if you have the strictNullChecks
compiler option set true. If you haven't enabled strictNullChecks
you cannot exclude null
from type
and the if
branch will be string
which is the same as string | null
so that leaves only never
for the else
.
Edit:
The reason why this doesn't work when strictNullChecks
is off is quite interesting. In that case the types string | null
and string
are identical. That means value
actually has the type string
and Exclude<string, null>
is simply string
(and therefore still includes null
), so the else
clause is left with type never
for value
.
Upvotes: 3