diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index df3528a17ac3c..27efc2eec5ade 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12053,6 +12053,10 @@ namespace ts { return sourceType; } + function isTypeEqualityComparableTo(source: Type, target: Type) { + return (target.flags & TypeFlags.Nullable) !== 0 || isTypeComparableTo(source, target); + } + function checkBinaryExpression(node: BinaryExpression, contextualMapper?: TypeMapper) { return checkBinaryLikeExpression(node.left, node.operatorToken, node.right, contextualMapper, node); } @@ -12166,15 +12170,17 @@ namespace ts { case SyntaxKind.GreaterThanToken: case SyntaxKind.LessThanEqualsToken: case SyntaxKind.GreaterThanEqualsToken: - if (!checkForDisallowedESSymbolOperand(operator)) { - return booleanType; + if (checkForDisallowedESSymbolOperand(operator)) { + if (!isTypeComparableTo(leftType, rightType) && !isTypeComparableTo(rightType, leftType)) { + reportOperatorError(); + } } - // Fall through + return booleanType; case SyntaxKind.EqualsEqualsToken: case SyntaxKind.ExclamationEqualsToken: case SyntaxKind.EqualsEqualsEqualsToken: case SyntaxKind.ExclamationEqualsEqualsToken: - if (!isTypeComparableTo(leftType, rightType) && !isTypeComparableTo(rightType, leftType)) { + if (!isTypeEqualityComparableTo(leftType, rightType) && !isTypeEqualityComparableTo(rightType, leftType)) { reportOperatorError(); } return booleanType; diff --git a/tests/baselines/reference/equalityStrictNulls.errors.txt b/tests/baselines/reference/equalityStrictNulls.errors.txt new file mode 100644 index 0000000000000..54b581c87e6e9 --- /dev/null +++ b/tests/baselines/reference/equalityStrictNulls.errors.txt @@ -0,0 +1,84 @@ +tests/cases/conformance/types/typeRelationships/comparable/equalityStrictNulls.ts(60,9): error TS2365: Operator '>' cannot be applied to types 'number' and 'undefined'. +tests/cases/conformance/types/typeRelationships/comparable/equalityStrictNulls.ts(62,9): error TS2365: Operator '<' cannot be applied to types 'number' and 'undefined'. +tests/cases/conformance/types/typeRelationships/comparable/equalityStrictNulls.ts(64,9): error TS2365: Operator '>=' cannot be applied to types 'number' and 'undefined'. +tests/cases/conformance/types/typeRelationships/comparable/equalityStrictNulls.ts(66,9): error TS2365: Operator '<=' cannot be applied to types 'number' and 'undefined'. + + +==== tests/cases/conformance/types/typeRelationships/comparable/equalityStrictNulls.ts (4 errors) ==== + + function f1(x: string) { + if (x == undefined) { + } + if (x != undefined) { + } + if (x === undefined) { + } + if (x !== undefined) { + } + if (x == null) { + } + if (x != null) { + } + if (x === null) { + } + if (x !== null) { + } + if (undefined == x) { + } + if (undefined != x) { + } + if (undefined === x) { + } + if (undefined !== x) { + } + if (null == x) { + } + if (null != x) { + } + if (null === x) { + } + if (null !== x) { + } + } + + function f2() { + if (undefined == undefined) { + } + if (undefined == null) { + } + if (null == undefined) { + } + if (null == null) { + } + } + + function f3(a: number, b: boolean, c: { x: number }, d: number | string) { + if (a == null) { + } + if (b == null) { + } + if (c == null) { + } + if (d == null) { + } + } + + function f4(x: number) { + if (x > undefined) { + ~~~~~~~~~~~~~ +!!! error TS2365: Operator '>' cannot be applied to types 'number' and 'undefined'. + } + if (x < undefined) { + ~~~~~~~~~~~~~ +!!! error TS2365: Operator '<' cannot be applied to types 'number' and 'undefined'. + } + if (x >= undefined) { + ~~~~~~~~~~~~~~ +!!! error TS2365: Operator '>=' cannot be applied to types 'number' and 'undefined'. + } + if (x <= undefined) { + ~~~~~~~~~~~~~~ +!!! error TS2365: Operator '<=' cannot be applied to types 'number' and 'undefined'. + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/equalityStrictNulls.js b/tests/baselines/reference/equalityStrictNulls.js new file mode 100644 index 0000000000000..99ff801a52cd1 --- /dev/null +++ b/tests/baselines/reference/equalityStrictNulls.js @@ -0,0 +1,136 @@ +//// [equalityStrictNulls.ts] + +function f1(x: string) { + if (x == undefined) { + } + if (x != undefined) { + } + if (x === undefined) { + } + if (x !== undefined) { + } + if (x == null) { + } + if (x != null) { + } + if (x === null) { + } + if (x !== null) { + } + if (undefined == x) { + } + if (undefined != x) { + } + if (undefined === x) { + } + if (undefined !== x) { + } + if (null == x) { + } + if (null != x) { + } + if (null === x) { + } + if (null !== x) { + } +} + +function f2() { + if (undefined == undefined) { + } + if (undefined == null) { + } + if (null == undefined) { + } + if (null == null) { + } +} + +function f3(a: number, b: boolean, c: { x: number }, d: number | string) { + if (a == null) { + } + if (b == null) { + } + if (c == null) { + } + if (d == null) { + } +} + +function f4(x: number) { + if (x > undefined) { + } + if (x < undefined) { + } + if (x >= undefined) { + } + if (x <= undefined) { + } +} + + +//// [equalityStrictNulls.js] +function f1(x) { + if (x == undefined) { + } + if (x != undefined) { + } + if (x === undefined) { + } + if (x !== undefined) { + } + if (x == null) { + } + if (x != null) { + } + if (x === null) { + } + if (x !== null) { + } + if (undefined == x) { + } + if (undefined != x) { + } + if (undefined === x) { + } + if (undefined !== x) { + } + if (null == x) { + } + if (null != x) { + } + if (null === x) { + } + if (null !== x) { + } +} +function f2() { + if (undefined == undefined) { + } + if (undefined == null) { + } + if (null == undefined) { + } + if (null == null) { + } +} +function f3(a, b, c, d) { + if (a == null) { + } + if (b == null) { + } + if (c == null) { + } + if (d == null) { + } +} +function f4(x) { + if (x > undefined) { + } + if (x < undefined) { + } + if (x >= undefined) { + } + if (x <= undefined) { + } +} diff --git a/tests/cases/conformance/types/typeRelationships/comparable/equalityStrictNulls.ts b/tests/cases/conformance/types/typeRelationships/comparable/equalityStrictNulls.ts new file mode 100644 index 0000000000000..6b2744e8849d7 --- /dev/null +++ b/tests/cases/conformance/types/typeRelationships/comparable/equalityStrictNulls.ts @@ -0,0 +1,69 @@ +// @strictNullChecks: true + +function f1(x: string) { + if (x == undefined) { + } + if (x != undefined) { + } + if (x === undefined) { + } + if (x !== undefined) { + } + if (x == null) { + } + if (x != null) { + } + if (x === null) { + } + if (x !== null) { + } + if (undefined == x) { + } + if (undefined != x) { + } + if (undefined === x) { + } + if (undefined !== x) { + } + if (null == x) { + } + if (null != x) { + } + if (null === x) { + } + if (null !== x) { + } +} + +function f2() { + if (undefined == undefined) { + } + if (undefined == null) { + } + if (null == undefined) { + } + if (null == null) { + } +} + +function f3(a: number, b: boolean, c: { x: number }, d: number | string) { + if (a == null) { + } + if (b == null) { + } + if (c == null) { + } + if (d == null) { + } +} + +function f4(x: number) { + if (x > undefined) { + } + if (x < undefined) { + } + if (x >= undefined) { + } + if (x <= undefined) { + } +}