Skip to content

Comparison operator is prohibited for nulls, but is allowed for union types containing the null type (with strictNullChecks turned on). #13863

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Nipheris opened this issue Feb 3, 2017 · 2 comments
Labels
Needs Investigation This issue needs a team member to investigate its status.

Comments

@Nipheris
Copy link

Nipheris commented Feb 3, 2017

TypeScript Version: 2.1.5

Code

--strictNullChecks should be enabled.

const nil = null;

// Compile error:
// "Operator '<' cannot be applied to types 'null' and 'number'"
if (nil < 10) { }

// Use function to trick the type narrowing
function test(): number | null {
    return null;
}

const n = test();
// OK
if (n < 1) { }

Expected behavior:
Both comparisons should generate a compilation error.

Actual behavior:
The first comparison (nil < 10) fails to compile (as expected), but the second one (n < 1) compiles successfully.

It seems odd that the same operation (less-than number) is not allowed for null (what is completely fine), but allowed for union type that includes null. If there are some solid reasons to behave this way, I think they should be mentioned in the language guide (can't find something about it).

@RyanCavanaugh
Copy link
Member

It seems odd that the same operation (less-than number) is not allowed for null (what is completely fine), but allowed for union type that includes null.

Critically, > is a comparison operator. Consider this example using the comparison operator ===:

declare var s: string;
declare var sn: number | string;
declare var n: number;
if (n === 1) { } // OK
if (n === "hello") { } // Error
if (s === 2) { } // Error
if (sn === "world") { } // OK
if (sn === 3) { } // OK

Is it odd that we can't compare a string to a number, but can compare a number to a string | number ? Well, not really. This is common and correct code.

When a comparison is inferred to be always false, that's a very bad sign (i.e. indicates a likely logic error). The comparison null > 0 is always false and is therefore suspicious. When the domain of a comparison operand includes some set of values which might make the result true, then the comparison makes sense again.

@Nipheris
Copy link
Author

Nipheris commented Feb 7, 2017

@RyanCavanaugh Thanks for the reply, I think I understood your position about the always-false comparisons. So, we have a sort of "unreachable code" that is prohibited by the type system.

By the way, it seems that null-s and undefined-s are a bit different beasts. Today I have checked the 2.2.0-rc, and it looks like that the comparisons with possibly-nulls are already prohibited. The second comparison in the topic description (if (n < 1) { }) fails to compile with the following error:

error TS2531: Object is possibly 'null'.

But if I change the code to be like this:

if (n !== null && n < 1) { }

it correctly narrows the type of n to number and compiles successfully.
The behavior of your example remains unchanged. So, there should be some fixes regarding the nulls, but I can't find them on the issue list or changelog.

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label May 24, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Investigation This issue needs a team member to investigate its status.
Projects
None yet
Development

No branches or pull requests

2 participants