From 483b92328db45fb56ef6ff73ebf9efe35cf2ec50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 8 Aug 2024 11:08:44 +0200 Subject: [PATCH 1/2] Don't special case nullable types in `isTypeEqualityComparableTo` --- src/compiler/checker.ts | 11 +- ...xpressionAssertionWithinTernary.errors.txt | 13 ++ ...ommaExpressionAssertionWithinTernary.types | 1 + .../reference/controlFlowIIFE.errors.txt | 5 +- .../controlFlowOptionalChain.errors.txt | 11 +- .../controlFlowOptionalChain2.errors.txt | 114 ++++++++++ ...arrowing(strictnullchecks=true).errors.txt | 83 +++++++ .../reference/equalityStrictNulls.errors.txt | 32 ++- .../reference/jsdocTypeTagCast.errors.txt | 5 +- .../reference/literalTypes1.errors.txt | 97 ++++++++ ...nouncheckedindexedaccess=false).errors.txt | 42 ++++ ...nouncheckedindexedaccess=false).errors.txt | 42 ++++ ...sEquality1(strictnullchecks=false).symbols | 128 +++++++++++ ...pesEquality1(strictnullchecks=false).types | 214 ++++++++++++++++++ ...quality1(strictnullchecks=true).errors.txt | 106 +++++++++ ...esEquality1(strictnullchecks=true).symbols | 128 +++++++++++ ...ypesEquality1(strictnullchecks=true).types | 214 ++++++++++++++++++ ...jectSpreadRepeatedNullCheckPerf.errors.txt | 142 ++++++++++++ ...teralAssignableToIndexSignature.errors.txt | 28 +++ ...wsIndexedAccessOfKnownProperty3.errors.txt | 15 ++ ...ledFunctionChecksInConditional2.errors.txt | 5 +- .../reference/unknownControlFlow.errors.txt | 8 +- .../nullableAndOtherTypesEquality1.ts | 79 +++++++ 23 files changed, 1512 insertions(+), 11 deletions(-) create mode 100644 tests/baselines/reference/controlFlowCommaExpressionAssertionWithinTernary.errors.txt create mode 100644 tests/baselines/reference/controlFlowOptionalChain2.errors.txt create mode 100644 tests/baselines/reference/emptyAnonymousObjectNarrowing(strictnullchecks=true).errors.txt create mode 100644 tests/baselines/reference/literalTypes1.errors.txt create mode 100644 tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=false).errors.txt create mode 100644 tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=false).errors.txt create mode 100644 tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=false).symbols create mode 100644 tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=false).types create mode 100644 tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).errors.txt create mode 100644 tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).symbols create mode 100644 tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).types create mode 100644 tests/baselines/reference/objectSpreadRepeatedNullCheckPerf.errors.txt create mode 100644 tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.errors.txt create mode 100644 tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty3.errors.txt create mode 100644 tests/cases/compiler/nullableAndOtherTypesEquality1.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 06346c66ba0ac..984555882df7e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -39487,8 +39487,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function isTypeEqualityComparableTo(source: Type, target: Type) { - return (target.flags & TypeFlags.Nullable) !== 0 || isTypeComparableTo(source, target); + function isTypeEqualityComparableTo(source: Type, target: Type, strictEq: boolean) { + return !strictEq && (target.flags & TypeFlags.Nullable) !== 0 || isTypeComparableTo(source, target); } function createCheckBinaryExpression() { @@ -39887,16 +39887,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // control flow analysis it is possible for operands to temporarily have narrower types, and those narrower // types may cause the operands to not be comparable. We don't want such errors reported (see #46475). if (!(checkMode && checkMode & CheckMode.TypeOnly)) { + const strictEq = operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken; if ( (isLiteralExpressionOfObject(left) || isLiteralExpressionOfObject(right)) && // only report for === and !== in JS, not == or != - (!isInJSFile(left) || (operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken)) + (!isInJSFile(left) || strictEq) ) { const eqType = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.EqualsEqualsEqualsToken; error(errorNode, Diagnostics.This_condition_will_always_return_0_since_JavaScript_compares_objects_by_reference_not_value, eqType ? "false" : "true"); } checkNaNEquality(errorNode, operator, left, right); - reportOperatorErrorUnless((left, right) => isTypeEqualityComparableTo(left, right) || isTypeEqualityComparableTo(right, left)); + reportOperatorErrorUnless((left, right) => isTypeEqualityComparableTo(left, right, strictEq) || isTypeEqualityComparableTo(right, left, strictEq)); } return booleanType; case SyntaxKind.InstanceOfKeyword: @@ -45516,7 +45517,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // to or from the type of the 'switch' expression. const caseType = checkExpression(clause.expression); - if (!isTypeEqualityComparableTo(expressionType, caseType)) { + if (!isTypeEqualityComparableTo(expressionType, caseType, /*strictEq*/ true)) { // expressionType is not comparable to caseType, try the reversed check and report errors if it fails checkTypeComparableTo(caseType, expressionType, clause.expression, /*headMessage*/ undefined); } diff --git a/tests/baselines/reference/controlFlowCommaExpressionAssertionWithinTernary.errors.txt b/tests/baselines/reference/controlFlowCommaExpressionAssertionWithinTernary.errors.txt new file mode 100644 index 0000000000000..6fc4642a8374c --- /dev/null +++ b/tests/baselines/reference/controlFlowCommaExpressionAssertionWithinTernary.errors.txt @@ -0,0 +1,13 @@ +controlFlowCommaExpressionAssertionWithinTernary.ts(5,26): error TS2367: This comparison appears to be unintentional because the types 'number | null' and 'undefined' have no overlap. + + +==== controlFlowCommaExpressionAssertionWithinTernary.ts (1 errors) ==== + declare function assert(value: any): asserts value; + + function foo2(param: number | null | undefined): number | null { + const val = param !== undefined; + return val ? (assert(param !== undefined), param) : null; + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number | null' and 'undefined' have no overlap. + // ^^^^^ Still typed as number | null | undefined + } \ No newline at end of file diff --git a/tests/baselines/reference/controlFlowCommaExpressionAssertionWithinTernary.types b/tests/baselines/reference/controlFlowCommaExpressionAssertionWithinTernary.types index 3574de9476c81..0ddc82e3378f4 100644 --- a/tests/baselines/reference/controlFlowCommaExpressionAssertionWithinTernary.types +++ b/tests/baselines/reference/controlFlowCommaExpressionAssertionWithinTernary.types @@ -5,6 +5,7 @@ declare function assert(value: any): asserts value; >assert : (value: any) => asserts value > : ^ ^^ ^^^^^ >value : any +> : ^^^ function foo2(param: number | null | undefined): number | null { >foo2 : (param: number | null | undefined) => number | null diff --git a/tests/baselines/reference/controlFlowIIFE.errors.txt b/tests/baselines/reference/controlFlowIIFE.errors.txt index 4be6c95ec20cb..2cbfa2f3e5dfb 100644 --- a/tests/baselines/reference/controlFlowIIFE.errors.txt +++ b/tests/baselines/reference/controlFlowIIFE.errors.txt @@ -1,8 +1,9 @@ +controlFlowIIFE.ts(36,5): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. controlFlowIIFE.ts(64,5): error TS2454: Variable 'v' is used before being assigned. controlFlowIIFE.ts(72,5): error TS2454: Variable 'v' is used before being assigned. -==== controlFlowIIFE.ts (2 errors) ==== +==== controlFlowIIFE.ts (3 errors) ==== declare function getStringOrNumber(): string | number; function f1() { @@ -39,6 +40,8 @@ controlFlowIIFE.ts(72,5): error TS2454: Variable 'v' is used before being assign })(); maybeNumber++; if (maybeNumber !== undefined) { + ~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. maybeNumber++; } diff --git a/tests/baselines/reference/controlFlowOptionalChain.errors.txt b/tests/baselines/reference/controlFlowOptionalChain.errors.txt index 1adac1bf02391..b8810e6489f2c 100644 --- a/tests/baselines/reference/controlFlowOptionalChain.errors.txt +++ b/tests/baselines/reference/controlFlowOptionalChain.errors.txt @@ -27,8 +27,11 @@ controlFlowOptionalChain.ts(223,9): error TS18048: 'o' is possibly 'undefined'. controlFlowOptionalChain.ts(238,9): error TS18048: 'o' is possibly 'undefined'. controlFlowOptionalChain.ts(241,9): error TS18048: 'o' is possibly 'undefined'. controlFlowOptionalChain.ts(244,9): error TS18048: 'o' is possibly 'undefined'. +controlFlowOptionalChain.ts(270,9): error TS2367: This comparison appears to be unintentional because the types 'string | number | undefined' and 'null' have no overlap. controlFlowOptionalChain.ts(271,9): error TS18048: 'o' is possibly 'undefined'. +controlFlowOptionalChain.ts(273,9): error TS2367: This comparison appears to be unintentional because the types 'string | number | undefined' and 'null' have no overlap. controlFlowOptionalChain.ts(274,9): error TS18048: 'o' is possibly 'undefined'. +controlFlowOptionalChain.ts(276,9): error TS2367: This comparison appears to be unintentional because the types 'number | undefined' and 'null' have no overlap. controlFlowOptionalChain.ts(277,9): error TS18048: 'o' is possibly 'undefined'. controlFlowOptionalChain.ts(307,9): error TS18048: 'o' is possibly 'undefined'. controlFlowOptionalChain.ts(310,9): error TS18048: 'o' is possibly 'undefined'. @@ -61,7 +64,7 @@ controlFlowOptionalChain.ts(518,13): error TS18048: 'o' is possibly 'undefined'. controlFlowOptionalChain.ts(567,21): error TS18048: 'someOptionalObject' is possibly 'undefined'. -==== controlFlowOptionalChain.ts (61 errors) ==== +==== controlFlowOptionalChain.ts (64 errors) ==== // assignments in shortcutting chain declare const o: undefined | { [key: string]: any; @@ -390,16 +393,22 @@ controlFlowOptionalChain.ts(567,21): error TS18048: 'someOptionalObject' is poss function f13a(o: Thing | undefined) { if (o?.foo !== null) { + ~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string | number | undefined' and 'null' have no overlap. o.foo; // Error ~ !!! error TS18048: 'o' is possibly 'undefined'. } if (o?.["foo"] !== null) { + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string | number | undefined' and 'null' have no overlap. o["foo"]; // Error ~ !!! error TS18048: 'o' is possibly 'undefined'. } if (o?.bar() !== null) { + ~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number | undefined' and 'null' have no overlap. o.bar; // Error ~ !!! error TS18048: 'o' is possibly 'undefined'. diff --git a/tests/baselines/reference/controlFlowOptionalChain2.errors.txt b/tests/baselines/reference/controlFlowOptionalChain2.errors.txt new file mode 100644 index 0000000000000..318dcbbf02de2 --- /dev/null +++ b/tests/baselines/reference/controlFlowOptionalChain2.errors.txt @@ -0,0 +1,114 @@ +controlFlowOptionalChain2.ts(71,9): error TS2367: This comparison appears to be unintentional because the types 'string | undefined' and 'null' have no overlap. +controlFlowOptionalChain2.ts(89,9): error TS2367: This comparison appears to be unintentional because the types 'string | undefined' and 'null' have no overlap. + + +==== controlFlowOptionalChain2.ts (2 errors) ==== + type A = { + type: 'A'; + name: string; + } + + type B = { + type: 'B'; + } + + function funcTwo(arg: A | B | undefined) { + if (arg?.type === 'B') { + arg; // `B` + return; + } + + arg; + arg?.name; + } + + function funcThree(arg: A | B | null) { + if (arg?.type === 'B') { + arg; // `B` + return; + } + + arg; + arg?.name; + } + + type U = { kind: undefined, u: 'u' } + type N = { kind: null, n: 'n' } + type X = { kind: 'X', x: 'x' } + + function f1(x: X | U | undefined) { + if (x?.kind === undefined) { + x; // U | undefined + } + else { + x; // X + } + } + + function f2(x: X | N | undefined) { + if (x?.kind === undefined) { + x; // undefined + } + else { + x; // X | N + } + } + + function f3(x: X | U | null) { + if (x?.kind === undefined) { + x; // U | null + } + else { + x; // X + } + } + + function f4(x: X | N | null) { + if (x?.kind === undefined) { + x; // null + } + else { + x; // X | N + } + } + + function f5(x: X | U | undefined) { + if (x?.kind === null) { + ~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string | undefined' and 'null' have no overlap. + x; // never + } + else { + x; // X | U | undefined + } + } + + function f6(x: X | N | undefined) { + if (x?.kind === null) { + x; // N + } + else { + x; // X | undefined + } + } + + function f7(x: X | U | null) { + if (x?.kind === null) { + ~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string | undefined' and 'null' have no overlap. + x; // never + } + else { + x; // X | U | null + } + } + + function f8(x: X | N | null) { + if (x?.kind === null) { + x; // N + } + else { + x; // X | null + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/emptyAnonymousObjectNarrowing(strictnullchecks=true).errors.txt b/tests/baselines/reference/emptyAnonymousObjectNarrowing(strictnullchecks=true).errors.txt new file mode 100644 index 0000000000000..0b1e5dc02279a --- /dev/null +++ b/tests/baselines/reference/emptyAnonymousObjectNarrowing(strictnullchecks=true).errors.txt @@ -0,0 +1,83 @@ +emptyAnonymousObjectNarrowing.ts(43,5): error TS2367: This comparison appears to be unintentional because the types '{}' and 'undefined' have no overlap. +emptyAnonymousObjectNarrowing.ts(50,5): error TS2367: This comparison appears to be unintentional because the types '{}' and 'null' have no overlap. + + +==== emptyAnonymousObjectNarrowing.ts (2 errors) ==== + declare let nonNull: {}; + if (nonNull === "foo") { + nonNull; + } + else { + nonNull; + } + + declare let obj: { a: string }; + if (nonNull === obj) { + nonNull; + } + else { + nonNull; + } + + function f1(x: T) { + if (nonNull === x) { + nonNull; + } + else { + nonNull; + } + } + + function f2(x: T) { + if (nonNull === x) { + nonNull; + } + else { + nonNull; + } + } + + declare let union: "xyz" | { a: string } | undefined; + if (nonNull === union) { + nonNull; + } + else { + nonNull; + } + + if (nonNull === undefined) { + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types '{}' and 'undefined' have no overlap. + nonNull; + } + else { + nonNull; + } + + if (nonNull === null) { + ~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types '{}' and 'null' have no overlap. + nonNull; + } + else { + nonNull; + } + + if (nonNull == undefined) { + nonNull; + } + else { + nonNull; + } + + // Repro from #50567 + const foo = (value: unknown): string => { + if (!value) { + return 'foo'; + } + if (value === 'xyz') { + return value; // Type '{}' is not assignable to type 'string'. + } + return ''; + }; + \ No newline at end of file diff --git a/tests/baselines/reference/equalityStrictNulls.errors.txt b/tests/baselines/reference/equalityStrictNulls.errors.txt index cf5df03539841..ed454b2948cca 100644 --- a/tests/baselines/reference/equalityStrictNulls.errors.txt +++ b/tests/baselines/reference/equalityStrictNulls.errors.txt @@ -1,42 +1,68 @@ +equalityStrictNulls.ts(6,9): error TS2367: This comparison appears to be unintentional because the types 'string' and 'undefined' have no overlap. +equalityStrictNulls.ts(8,9): error TS2367: This comparison appears to be unintentional because the types 'string' and 'undefined' have no overlap. +equalityStrictNulls.ts(14,9): error TS2367: This comparison appears to be unintentional because the types 'string' and 'null' have no overlap. +equalityStrictNulls.ts(16,9): error TS2367: This comparison appears to be unintentional because the types 'string' and 'null' have no overlap. +equalityStrictNulls.ts(22,9): error TS2367: This comparison appears to be unintentional because the types 'undefined' and 'string' have no overlap. +equalityStrictNulls.ts(24,9): error TS2367: This comparison appears to be unintentional because the types 'undefined' and 'string' have no overlap. +equalityStrictNulls.ts(30,9): error TS2367: This comparison appears to be unintentional because the types 'null' and 'string' have no overlap. +equalityStrictNulls.ts(32,9): error TS2367: This comparison appears to be unintentional because the types 'null' and 'string' have no overlap. equalityStrictNulls.ts(59,13): error TS18050: The value 'undefined' cannot be used here. equalityStrictNulls.ts(61,13): error TS18050: The value 'undefined' cannot be used here. equalityStrictNulls.ts(63,14): error TS18050: The value 'undefined' cannot be used here. equalityStrictNulls.ts(65,14): error TS18050: The value 'undefined' cannot be used here. +equalityStrictNulls.ts(70,14): error TS2678: Type 'null' is not comparable to type 'string'. +equalityStrictNulls.ts(72,14): error TS2678: Type 'undefined' is not comparable to type 'string'. -==== equalityStrictNulls.ts (4 errors) ==== +==== equalityStrictNulls.ts (14 errors) ==== function f1(x: string) { if (x == undefined) { } if (x != undefined) { } if (x === undefined) { + ~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string' and 'undefined' have no overlap. } if (x !== undefined) { + ~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string' and 'undefined' have no overlap. } if (x == null) { } if (x != null) { } if (x === null) { + ~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string' and 'null' have no overlap. } if (x !== null) { + ~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string' and 'null' have no overlap. } if (undefined == x) { } if (undefined != x) { } if (undefined === x) { + ~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'undefined' and 'string' have no overlap. } if (undefined !== x) { + ~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'undefined' and 'string' have no overlap. } if (null == x) { } if (null != x) { } if (null === x) { + ~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'null' and 'string' have no overlap. } if (null !== x) { + ~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'null' and 'string' have no overlap. } } @@ -83,8 +109,12 @@ equalityStrictNulls.ts(65,14): error TS18050: The value 'undefined' cannot be us function f5(x: string) { switch(x) { case null: + ~~~~ +!!! error TS2678: Type 'null' is not comparable to type 'string'. break; case undefined: + ~~~~~~~~~ +!!! error TS2678: Type 'undefined' is not comparable to type 'string'. break; default: return; diff --git a/tests/baselines/reference/jsdocTypeTagCast.errors.txt b/tests/baselines/reference/jsdocTypeTagCast.errors.txt index 4e972729d9a49..cb88814cf3a43 100644 --- a/tests/baselines/reference/jsdocTypeTagCast.errors.txt +++ b/tests/baselines/reference/jsdocTypeTagCast.errors.txt @@ -13,6 +13,7 @@ b.js(58,1): error TS2322: Type 'SomeFakeClass' is not assignable to type 'SomeBa Type 'string' is not assignable to type 'number'. b.js(66,15): error TS1228: A type predicate is only allowed in return type position for functions and methods. b.js(66,38): error TS2454: Variable 'numOrStr' is used before being assigned. +b.js(66,38): error TS2367: This comparison appears to be unintentional because the types 'string | number' and 'undefined' have no overlap. b.js(67,2): error TS2322: Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'. b.js(67,8): error TS2454: Variable 'numOrStr' is used before being assigned. @@ -21,7 +22,7 @@ b.js(67,8): error TS2454: Variable 'numOrStr' is used before being assigned. ==== a.ts (0 errors) ==== var W: string; -==== b.js (10 errors) ==== +==== b.js (11 errors) ==== // @ts-check var W = /** @type {string} */(/** @type {*} */ (4)); @@ -114,6 +115,8 @@ b.js(67,8): error TS2454: Variable 'numOrStr' is used before being assigned. !!! error TS1228: A type predicate is only allowed in return type position for functions and methods. ~~~~~~~~ !!! error TS2454: Variable 'numOrStr' is used before being assigned. + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string | number' and 'undefined' have no overlap. str = numOrStr; // Error, no narrowing occurred ~~~ !!! error TS2322: Type 'string | number' is not assignable to type 'string'. diff --git a/tests/baselines/reference/literalTypes1.errors.txt b/tests/baselines/reference/literalTypes1.errors.txt new file mode 100644 index 0000000000000..e1247c714ce5b --- /dev/null +++ b/tests/baselines/reference/literalTypes1.errors.txt @@ -0,0 +1,97 @@ +literalTypes1.ts(58,14): error TS2678: Type 'null' is not comparable to type 'string | true | 0 | 1'. +literalTypes1.ts(61,14): error TS2678: Type 'undefined' is not comparable to type 'string | true | 0 | 1'. + + +==== literalTypes1.ts (2 errors) ==== + let zero: 0 = 0; + let one: 1 = 1; + let two: 2 = 2; + let oneOrTwo: 1 | 2 = <1 | 2>1; + + function f1(x: 0 | 1 | 2) { + switch (x) { + case zero: + x; + break; + case one: + x; + break; + case two: + x; + break; + default: + x; + } + } + + function f2(x: 0 | 1 | 2) { + switch (x) { + case zero: + x; + break; + case oneOrTwo: + x; + break; + default: + x; + } + } + + type Falsy = false | 0 | "" | null | undefined; + + function f3(x: Falsy) { + if (x) { + x; + } + else { + x; + } + } + + function f4(x: 0 | 1 | true | string) { + switch (x) { + case 0: + x; + break; + case 1: + x; + break; + case "abc": + case "def": + x; + break; + case null: + ~~~~ +!!! error TS2678: Type 'null' is not comparable to type 'string | true | 0 | 1'. + x; + break; + case undefined: + ~~~~~~~~~ +!!! error TS2678: Type 'undefined' is not comparable to type 'string | true | 0 | 1'. + x; + break; + default: + x; + } + } + + function f5(x: string | number | boolean) { + switch (x) { + case "abc": + x; + break; + case 0: + case 1: + x; + break; + case true: + x; + break; + case "hello": + case 123: + x; + break; + default: + x; + } + } \ No newline at end of file diff --git a/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=false).errors.txt b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=false).errors.txt new file mode 100644 index 0000000000000..d790d07bad9b0 --- /dev/null +++ b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=false).errors.txt @@ -0,0 +1,42 @@ +narrowBySwitchDiscriminantUndefinedCase1.ts(24,10): error TS2678: Type 'undefined' is not comparable to type '"hello"'. + + +==== narrowBySwitchDiscriminantUndefinedCase1.ts (1 errors) ==== + // https://github.com/microsoft/TypeScript/issues/57999 + + interface A { + optionalProp?: "hello"; + } + + function func(arg: A) { + const { optionalProp } = arg; + + switch (optionalProp) { + case undefined: + return undefined; + case "hello": + return "hello"; + default: + assertUnreachable(optionalProp); + } + } + + function func2() { + const optionalProp = ["hello" as const][Math.random()]; + + switch (optionalProp) { + case undefined: + ~~~~~~~~~ +!!! error TS2678: Type 'undefined' is not comparable to type '"hello"'. + return undefined; + case "hello": + return "hello"; + default: + assertUnreachable(optionalProp); + } + } + + function assertUnreachable(_: never): never { + throw new Error("Unreachable path taken"); + } + \ No newline at end of file diff --git a/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=false).errors.txt b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=false).errors.txt new file mode 100644 index 0000000000000..d790d07bad9b0 --- /dev/null +++ b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=false).errors.txt @@ -0,0 +1,42 @@ +narrowBySwitchDiscriminantUndefinedCase1.ts(24,10): error TS2678: Type 'undefined' is not comparable to type '"hello"'. + + +==== narrowBySwitchDiscriminantUndefinedCase1.ts (1 errors) ==== + // https://github.com/microsoft/TypeScript/issues/57999 + + interface A { + optionalProp?: "hello"; + } + + function func(arg: A) { + const { optionalProp } = arg; + + switch (optionalProp) { + case undefined: + return undefined; + case "hello": + return "hello"; + default: + assertUnreachable(optionalProp); + } + } + + function func2() { + const optionalProp = ["hello" as const][Math.random()]; + + switch (optionalProp) { + case undefined: + ~~~~~~~~~ +!!! error TS2678: Type 'undefined' is not comparable to type '"hello"'. + return undefined; + case "hello": + return "hello"; + default: + assertUnreachable(optionalProp); + } + } + + function assertUnreachable(_: never): never { + throw new Error("Unreachable path taken"); + } + \ No newline at end of file diff --git a/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=false).symbols b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=false).symbols new file mode 100644 index 0000000000000..d3015e2b719de --- /dev/null +++ b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=false).symbols @@ -0,0 +1,128 @@ +//// [tests/cases/compiler/nullableAndOtherTypesEquality1.ts] //// + +=== nullableAndOtherTypesEquality1.ts === +// https://github.com/microsoft/TypeScript/issues/11920 + +if (null === undefined) { +>undefined : Symbol(undefined) +} +if (null == undefined) { +>undefined : Symbol(undefined) +} + +declare const str: string; +>str : Symbol(str, Decl(nullableAndOtherTypesEquality1.ts, 7, 13)) + +declare const strOrNull: string | null; +>strOrNull : Symbol(strOrNull, Decl(nullableAndOtherTypesEquality1.ts, 8, 13)) + +declare const strOrUndef: string | undefined; +>strOrUndef : Symbol(strOrUndef, Decl(nullableAndOtherTypesEquality1.ts, 9, 13)) + +declare const strOrNullUndef: string | null | undefined; +>strOrNullUndef : Symbol(strOrNullUndef, Decl(nullableAndOtherTypesEquality1.ts, 10, 13)) + +if (str === null) { +>str : Symbol(str, Decl(nullableAndOtherTypesEquality1.ts, 7, 13)) +} +if (str === undefined) { +>str : Symbol(str, Decl(nullableAndOtherTypesEquality1.ts, 7, 13)) +>undefined : Symbol(undefined) +} +if (str == null) { +>str : Symbol(str, Decl(nullableAndOtherTypesEquality1.ts, 7, 13)) +} +if (str == undefined) { +>str : Symbol(str, Decl(nullableAndOtherTypesEquality1.ts, 7, 13)) +>undefined : Symbol(undefined) +} + +switch (str) { +>str : Symbol(str, Decl(nullableAndOtherTypesEquality1.ts, 7, 13)) + + case null: + case undefined: +>undefined : Symbol(undefined) + + case "a": + default: +} + +if (strOrNull === null) { +>strOrNull : Symbol(strOrNull, Decl(nullableAndOtherTypesEquality1.ts, 8, 13)) +} +if (strOrNull === undefined) { +>strOrNull : Symbol(strOrNull, Decl(nullableAndOtherTypesEquality1.ts, 8, 13)) +>undefined : Symbol(undefined) +} +if (strOrNull == null) { +>strOrNull : Symbol(strOrNull, Decl(nullableAndOtherTypesEquality1.ts, 8, 13)) +} +if (strOrNull == undefined) { +>strOrNull : Symbol(strOrNull, Decl(nullableAndOtherTypesEquality1.ts, 8, 13)) +>undefined : Symbol(undefined) +} + +switch (strOrNull) { +>strOrNull : Symbol(strOrNull, Decl(nullableAndOtherTypesEquality1.ts, 8, 13)) + + case null: + case undefined: +>undefined : Symbol(undefined) + + case "a": + default: +} + +if (strOrUndef === null) { +>strOrUndef : Symbol(strOrUndef, Decl(nullableAndOtherTypesEquality1.ts, 9, 13)) +} +if (strOrUndef === undefined) { +>strOrUndef : Symbol(strOrUndef, Decl(nullableAndOtherTypesEquality1.ts, 9, 13)) +>undefined : Symbol(undefined) +} +if (strOrUndef == null) { +>strOrUndef : Symbol(strOrUndef, Decl(nullableAndOtherTypesEquality1.ts, 9, 13)) +} +if (strOrUndef == undefined) { +>strOrUndef : Symbol(strOrUndef, Decl(nullableAndOtherTypesEquality1.ts, 9, 13)) +>undefined : Symbol(undefined) +} + +switch (strOrUndef) { +>strOrUndef : Symbol(strOrUndef, Decl(nullableAndOtherTypesEquality1.ts, 9, 13)) + + case null: + case undefined: +>undefined : Symbol(undefined) + + case "a": + default: +} + +if (strOrNullUndef === null) { +>strOrNullUndef : Symbol(strOrNullUndef, Decl(nullableAndOtherTypesEquality1.ts, 10, 13)) +} +if (strOrNullUndef === undefined) { +>strOrNullUndef : Symbol(strOrNullUndef, Decl(nullableAndOtherTypesEquality1.ts, 10, 13)) +>undefined : Symbol(undefined) +} +if (strOrNullUndef == null) { +>strOrNullUndef : Symbol(strOrNullUndef, Decl(nullableAndOtherTypesEquality1.ts, 10, 13)) +} +if (strOrNullUndef == undefined) { +>strOrNullUndef : Symbol(strOrNullUndef, Decl(nullableAndOtherTypesEquality1.ts, 10, 13)) +>undefined : Symbol(undefined) +} + +switch (strOrNullUndef) { +>strOrNullUndef : Symbol(strOrNullUndef, Decl(nullableAndOtherTypesEquality1.ts, 10, 13)) + + case null: + case undefined: +>undefined : Symbol(undefined) + + case "a": + default: +} + diff --git a/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=false).types b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=false).types new file mode 100644 index 0000000000000..65e463f832246 --- /dev/null +++ b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=false).types @@ -0,0 +1,214 @@ +//// [tests/cases/compiler/nullableAndOtherTypesEquality1.ts] //// + +=== nullableAndOtherTypesEquality1.ts === +// https://github.com/microsoft/TypeScript/issues/11920 + +if (null === undefined) { +>null === undefined : boolean +> : ^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} +if (null == undefined) { +>null == undefined : boolean +> : ^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} + +declare const str: string; +>str : string +> : ^^^^^^ + +declare const strOrNull: string | null; +>strOrNull : string +> : ^^^^^^ + +declare const strOrUndef: string | undefined; +>strOrUndef : string +> : ^^^^^^ + +declare const strOrNullUndef: string | null | undefined; +>strOrNullUndef : string +> : ^^^^^^ + +if (str === null) { +>str === null : boolean +> : ^^^^^^^ +>str : string +> : ^^^^^^ +} +if (str === undefined) { +>str === undefined : boolean +> : ^^^^^^^ +>str : string +> : ^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} +if (str == null) { +>str == null : boolean +> : ^^^^^^^ +>str : string +> : ^^^^^^ +} +if (str == undefined) { +>str == undefined : boolean +> : ^^^^^^^ +>str : string +> : ^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} + +switch (str) { +>str : string +> : ^^^^^^ + + case null: + case undefined: +>undefined : undefined +> : ^^^^^^^^^ + + case "a": +>"a" : "a" +> : ^^^ + + default: +} + +if (strOrNull === null) { +>strOrNull === null : boolean +> : ^^^^^^^ +>strOrNull : string +> : ^^^^^^ +} +if (strOrNull === undefined) { +>strOrNull === undefined : boolean +> : ^^^^^^^ +>strOrNull : string +> : ^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} +if (strOrNull == null) { +>strOrNull == null : boolean +> : ^^^^^^^ +>strOrNull : string +> : ^^^^^^ +} +if (strOrNull == undefined) { +>strOrNull == undefined : boolean +> : ^^^^^^^ +>strOrNull : string +> : ^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} + +switch (strOrNull) { +>strOrNull : string +> : ^^^^^^ + + case null: + case undefined: +>undefined : undefined +> : ^^^^^^^^^ + + case "a": +>"a" : "a" +> : ^^^ + + default: +} + +if (strOrUndef === null) { +>strOrUndef === null : boolean +> : ^^^^^^^ +>strOrUndef : string +> : ^^^^^^ +} +if (strOrUndef === undefined) { +>strOrUndef === undefined : boolean +> : ^^^^^^^ +>strOrUndef : string +> : ^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} +if (strOrUndef == null) { +>strOrUndef == null : boolean +> : ^^^^^^^ +>strOrUndef : string +> : ^^^^^^ +} +if (strOrUndef == undefined) { +>strOrUndef == undefined : boolean +> : ^^^^^^^ +>strOrUndef : string +> : ^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} + +switch (strOrUndef) { +>strOrUndef : string +> : ^^^^^^ + + case null: + case undefined: +>undefined : undefined +> : ^^^^^^^^^ + + case "a": +>"a" : "a" +> : ^^^ + + default: +} + +if (strOrNullUndef === null) { +>strOrNullUndef === null : boolean +> : ^^^^^^^ +>strOrNullUndef : string +> : ^^^^^^ +} +if (strOrNullUndef === undefined) { +>strOrNullUndef === undefined : boolean +> : ^^^^^^^ +>strOrNullUndef : string +> : ^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} +if (strOrNullUndef == null) { +>strOrNullUndef == null : boolean +> : ^^^^^^^ +>strOrNullUndef : string +> : ^^^^^^ +} +if (strOrNullUndef == undefined) { +>strOrNullUndef == undefined : boolean +> : ^^^^^^^ +>strOrNullUndef : string +> : ^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} + +switch (strOrNullUndef) { +>strOrNullUndef : string +> : ^^^^^^ + + case null: + case undefined: +>undefined : undefined +> : ^^^^^^^^^ + + case "a": +>"a" : "a" +> : ^^^ + + default: +} + diff --git a/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).errors.txt b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).errors.txt new file mode 100644 index 0000000000000..cbb6596ec7420 --- /dev/null +++ b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).errors.txt @@ -0,0 +1,106 @@ +nullableAndOtherTypesEquality1.ts(3,5): error TS2367: This comparison appears to be unintentional because the types 'null' and 'undefined' have no overlap. +nullableAndOtherTypesEquality1.ts(13,5): error TS2367: This comparison appears to be unintentional because the types 'string' and 'null' have no overlap. +nullableAndOtherTypesEquality1.ts(15,5): error TS2367: This comparison appears to be unintentional because the types 'string' and 'undefined' have no overlap. +nullableAndOtherTypesEquality1.ts(23,8): error TS2678: Type 'null' is not comparable to type 'string'. +nullableAndOtherTypesEquality1.ts(24,8): error TS2678: Type 'undefined' is not comparable to type 'string'. +nullableAndOtherTypesEquality1.ts(31,5): error TS2367: This comparison appears to be unintentional because the types 'string | null' and 'undefined' have no overlap. +nullableAndOtherTypesEquality1.ts(40,8): error TS2678: Type 'undefined' is not comparable to type 'string | null'. +nullableAndOtherTypesEquality1.ts(45,5): error TS2367: This comparison appears to be unintentional because the types 'string | undefined' and 'null' have no overlap. +nullableAndOtherTypesEquality1.ts(55,8): error TS2678: Type 'null' is not comparable to type 'string | undefined'. + + +==== nullableAndOtherTypesEquality1.ts (9 errors) ==== + // https://github.com/microsoft/TypeScript/issues/11920 + + if (null === undefined) { + ~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'null' and 'undefined' have no overlap. + } + if (null == undefined) { + } + + declare const str: string; + declare const strOrNull: string | null; + declare const strOrUndef: string | undefined; + declare const strOrNullUndef: string | null | undefined; + + if (str === null) { + ~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string' and 'null' have no overlap. + } + if (str === undefined) { + ~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string' and 'undefined' have no overlap. + } + if (str == null) { + } + if (str == undefined) { + } + + switch (str) { + case null: + ~~~~ +!!! error TS2678: Type 'null' is not comparable to type 'string'. + case undefined: + ~~~~~~~~~ +!!! error TS2678: Type 'undefined' is not comparable to type 'string'. + case "a": + default: + } + + if (strOrNull === null) { + } + if (strOrNull === undefined) { + ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string | null' and 'undefined' have no overlap. + } + if (strOrNull == null) { + } + if (strOrNull == undefined) { + } + + switch (strOrNull) { + case null: + case undefined: + ~~~~~~~~~ +!!! error TS2678: Type 'undefined' is not comparable to type 'string | null'. + case "a": + default: + } + + if (strOrUndef === null) { + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string | undefined' and 'null' have no overlap. + } + if (strOrUndef === undefined) { + } + if (strOrUndef == null) { + } + if (strOrUndef == undefined) { + } + + switch (strOrUndef) { + case null: + ~~~~ +!!! error TS2678: Type 'null' is not comparable to type 'string | undefined'. + case undefined: + case "a": + default: + } + + if (strOrNullUndef === null) { + } + if (strOrNullUndef === undefined) { + } + if (strOrNullUndef == null) { + } + if (strOrNullUndef == undefined) { + } + + switch (strOrNullUndef) { + case null: + case undefined: + case "a": + default: + } + \ No newline at end of file diff --git a/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).symbols b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).symbols new file mode 100644 index 0000000000000..d3015e2b719de --- /dev/null +++ b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).symbols @@ -0,0 +1,128 @@ +//// [tests/cases/compiler/nullableAndOtherTypesEquality1.ts] //// + +=== nullableAndOtherTypesEquality1.ts === +// https://github.com/microsoft/TypeScript/issues/11920 + +if (null === undefined) { +>undefined : Symbol(undefined) +} +if (null == undefined) { +>undefined : Symbol(undefined) +} + +declare const str: string; +>str : Symbol(str, Decl(nullableAndOtherTypesEquality1.ts, 7, 13)) + +declare const strOrNull: string | null; +>strOrNull : Symbol(strOrNull, Decl(nullableAndOtherTypesEquality1.ts, 8, 13)) + +declare const strOrUndef: string | undefined; +>strOrUndef : Symbol(strOrUndef, Decl(nullableAndOtherTypesEquality1.ts, 9, 13)) + +declare const strOrNullUndef: string | null | undefined; +>strOrNullUndef : Symbol(strOrNullUndef, Decl(nullableAndOtherTypesEquality1.ts, 10, 13)) + +if (str === null) { +>str : Symbol(str, Decl(nullableAndOtherTypesEquality1.ts, 7, 13)) +} +if (str === undefined) { +>str : Symbol(str, Decl(nullableAndOtherTypesEquality1.ts, 7, 13)) +>undefined : Symbol(undefined) +} +if (str == null) { +>str : Symbol(str, Decl(nullableAndOtherTypesEquality1.ts, 7, 13)) +} +if (str == undefined) { +>str : Symbol(str, Decl(nullableAndOtherTypesEquality1.ts, 7, 13)) +>undefined : Symbol(undefined) +} + +switch (str) { +>str : Symbol(str, Decl(nullableAndOtherTypesEquality1.ts, 7, 13)) + + case null: + case undefined: +>undefined : Symbol(undefined) + + case "a": + default: +} + +if (strOrNull === null) { +>strOrNull : Symbol(strOrNull, Decl(nullableAndOtherTypesEquality1.ts, 8, 13)) +} +if (strOrNull === undefined) { +>strOrNull : Symbol(strOrNull, Decl(nullableAndOtherTypesEquality1.ts, 8, 13)) +>undefined : Symbol(undefined) +} +if (strOrNull == null) { +>strOrNull : Symbol(strOrNull, Decl(nullableAndOtherTypesEquality1.ts, 8, 13)) +} +if (strOrNull == undefined) { +>strOrNull : Symbol(strOrNull, Decl(nullableAndOtherTypesEquality1.ts, 8, 13)) +>undefined : Symbol(undefined) +} + +switch (strOrNull) { +>strOrNull : Symbol(strOrNull, Decl(nullableAndOtherTypesEquality1.ts, 8, 13)) + + case null: + case undefined: +>undefined : Symbol(undefined) + + case "a": + default: +} + +if (strOrUndef === null) { +>strOrUndef : Symbol(strOrUndef, Decl(nullableAndOtherTypesEquality1.ts, 9, 13)) +} +if (strOrUndef === undefined) { +>strOrUndef : Symbol(strOrUndef, Decl(nullableAndOtherTypesEquality1.ts, 9, 13)) +>undefined : Symbol(undefined) +} +if (strOrUndef == null) { +>strOrUndef : Symbol(strOrUndef, Decl(nullableAndOtherTypesEquality1.ts, 9, 13)) +} +if (strOrUndef == undefined) { +>strOrUndef : Symbol(strOrUndef, Decl(nullableAndOtherTypesEquality1.ts, 9, 13)) +>undefined : Symbol(undefined) +} + +switch (strOrUndef) { +>strOrUndef : Symbol(strOrUndef, Decl(nullableAndOtherTypesEquality1.ts, 9, 13)) + + case null: + case undefined: +>undefined : Symbol(undefined) + + case "a": + default: +} + +if (strOrNullUndef === null) { +>strOrNullUndef : Symbol(strOrNullUndef, Decl(nullableAndOtherTypesEquality1.ts, 10, 13)) +} +if (strOrNullUndef === undefined) { +>strOrNullUndef : Symbol(strOrNullUndef, Decl(nullableAndOtherTypesEquality1.ts, 10, 13)) +>undefined : Symbol(undefined) +} +if (strOrNullUndef == null) { +>strOrNullUndef : Symbol(strOrNullUndef, Decl(nullableAndOtherTypesEquality1.ts, 10, 13)) +} +if (strOrNullUndef == undefined) { +>strOrNullUndef : Symbol(strOrNullUndef, Decl(nullableAndOtherTypesEquality1.ts, 10, 13)) +>undefined : Symbol(undefined) +} + +switch (strOrNullUndef) { +>strOrNullUndef : Symbol(strOrNullUndef, Decl(nullableAndOtherTypesEquality1.ts, 10, 13)) + + case null: + case undefined: +>undefined : Symbol(undefined) + + case "a": + default: +} + diff --git a/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).types b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).types new file mode 100644 index 0000000000000..40044341ab0e0 --- /dev/null +++ b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).types @@ -0,0 +1,214 @@ +//// [tests/cases/compiler/nullableAndOtherTypesEquality1.ts] //// + +=== nullableAndOtherTypesEquality1.ts === +// https://github.com/microsoft/TypeScript/issues/11920 + +if (null === undefined) { +>null === undefined : boolean +> : ^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} +if (null == undefined) { +>null == undefined : boolean +> : ^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} + +declare const str: string; +>str : string +> : ^^^^^^ + +declare const strOrNull: string | null; +>strOrNull : string | null +> : ^^^^^^^^^^^^^ + +declare const strOrUndef: string | undefined; +>strOrUndef : string | undefined +> : ^^^^^^^^^^^^^^^^^^ + +declare const strOrNullUndef: string | null | undefined; +>strOrNullUndef : string | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + +if (str === null) { +>str === null : boolean +> : ^^^^^^^ +>str : string +> : ^^^^^^ +} +if (str === undefined) { +>str === undefined : boolean +> : ^^^^^^^ +>str : string +> : ^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} +if (str == null) { +>str == null : boolean +> : ^^^^^^^ +>str : string +> : ^^^^^^ +} +if (str == undefined) { +>str == undefined : boolean +> : ^^^^^^^ +>str : string +> : ^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} + +switch (str) { +>str : string +> : ^^^^^^ + + case null: + case undefined: +>undefined : undefined +> : ^^^^^^^^^ + + case "a": +>"a" : "a" +> : ^^^ + + default: +} + +if (strOrNull === null) { +>strOrNull === null : boolean +> : ^^^^^^^ +>strOrNull : string | null +> : ^^^^^^^^^^^^^ +} +if (strOrNull === undefined) { +>strOrNull === undefined : boolean +> : ^^^^^^^ +>strOrNull : string | null +> : ^^^^^^^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} +if (strOrNull == null) { +>strOrNull == null : boolean +> : ^^^^^^^ +>strOrNull : string | null +> : ^^^^^^^^^^^^^ +} +if (strOrNull == undefined) { +>strOrNull == undefined : boolean +> : ^^^^^^^ +>strOrNull : string | null +> : ^^^^^^^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} + +switch (strOrNull) { +>strOrNull : string | null +> : ^^^^^^^^^^^^^ + + case null: + case undefined: +>undefined : undefined +> : ^^^^^^^^^ + + case "a": +>"a" : "a" +> : ^^^ + + default: +} + +if (strOrUndef === null) { +>strOrUndef === null : boolean +> : ^^^^^^^ +>strOrUndef : string | undefined +> : ^^^^^^^^^^^^^^^^^^ +} +if (strOrUndef === undefined) { +>strOrUndef === undefined : boolean +> : ^^^^^^^ +>strOrUndef : string | undefined +> : ^^^^^^^^^^^^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} +if (strOrUndef == null) { +>strOrUndef == null : boolean +> : ^^^^^^^ +>strOrUndef : string | undefined +> : ^^^^^^^^^^^^^^^^^^ +} +if (strOrUndef == undefined) { +>strOrUndef == undefined : boolean +> : ^^^^^^^ +>strOrUndef : string | undefined +> : ^^^^^^^^^^^^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} + +switch (strOrUndef) { +>strOrUndef : string | undefined +> : ^^^^^^^^^^^^^^^^^^ + + case null: + case undefined: +>undefined : undefined +> : ^^^^^^^^^ + + case "a": +>"a" : "a" +> : ^^^ + + default: +} + +if (strOrNullUndef === null) { +>strOrNullUndef === null : boolean +> : ^^^^^^^ +>strOrNullUndef : string | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +} +if (strOrNullUndef === undefined) { +>strOrNullUndef === undefined : boolean +> : ^^^^^^^ +>strOrNullUndef : string | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} +if (strOrNullUndef == null) { +>strOrNullUndef == null : boolean +> : ^^^^^^^ +>strOrNullUndef : string | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +} +if (strOrNullUndef == undefined) { +>strOrNullUndef == undefined : boolean +> : ^^^^^^^ +>strOrNullUndef : string | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} + +switch (strOrNullUndef) { +>strOrNullUndef : string | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + + case null: + case undefined: +>undefined : undefined +> : ^^^^^^^^^ + + case "a": +>"a" : "a" +> : ^^^ + + default: +} + diff --git a/tests/baselines/reference/objectSpreadRepeatedNullCheckPerf.errors.txt b/tests/baselines/reference/objectSpreadRepeatedNullCheckPerf.errors.txt new file mode 100644 index 0000000000000..8ac5cfbaa8853 --- /dev/null +++ b/tests/baselines/reference/objectSpreadRepeatedNullCheckPerf.errors.txt @@ -0,0 +1,142 @@ +objectSpreadRepeatedNullCheckPerf.ts(32,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(33,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(34,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(35,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(36,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(37,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(38,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(39,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(40,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(41,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(42,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(43,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(44,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(45,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(46,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(47,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(48,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(49,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(50,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(51,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(52,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(53,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(54,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(55,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(56,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. +objectSpreadRepeatedNullCheckPerf.ts(57,12): error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + + +==== objectSpreadRepeatedNullCheckPerf.ts (26 errors) ==== + interface Props { + readonly a?: string + readonly b?: string + readonly c?: string + readonly d?: string + readonly e?: string + readonly f?: string + readonly g?: string + readonly h?: string + readonly i?: string + readonly j?: string + readonly k?: string + readonly l?: string + readonly m?: string + readonly n?: string + readonly o?: string + readonly p?: string + readonly q?: string + readonly r?: string + readonly s?: string + readonly t?: string + readonly u?: string + readonly v?: string + readonly w?: string + readonly x?: string + readonly y?: string + readonly z?: string + } + + function parseWithSpread(config: Record): Props { + return { + ...config.a !== undefined && { a: config.a.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.b !== undefined && { b: config.b.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.c !== undefined && { c: config.c.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.d !== undefined && { d: config.d.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.e !== undefined && { e: config.e.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.f !== undefined && { f: config.f.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.g !== undefined && { g: config.g.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.h !== undefined && { h: config.h.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.i !== undefined && { i: config.i.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.j !== undefined && { j: config.j.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.k !== undefined && { k: config.k.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.l !== undefined && { l: config.l.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.m !== undefined && { m: config.m.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.n !== undefined && { n: config.n.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.o !== undefined && { o: config.o.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.p !== undefined && { p: config.p.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.q !== undefined && { q: config.q.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.r !== undefined && { r: config.r.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.s !== undefined && { s: config.s.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.t !== undefined && { t: config.t.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.u !== undefined && { u: config.u.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.v !== undefined && { v: config.v.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.w !== undefined && { w: config.w.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.x !== undefined && { x: config.x.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.y !== undefined && { y: config.y.toString() }, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + ...config.z !== undefined && { z: config.z.toString() } + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'number' and 'undefined' have no overlap. + } + } + + parseWithSpread({ a: 1, b: 2, z: 26 }) \ No newline at end of file diff --git a/tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.errors.txt b/tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.errors.txt new file mode 100644 index 0000000000000..0b0578e80c2fc --- /dev/null +++ b/tests/baselines/reference/spreadOfObjectLiteralAssignableToIndexSignature.errors.txt @@ -0,0 +1,28 @@ +spreadOfObjectLiteralAssignableToIndexSignature.ts(5,30): error TS2367: This comparison appears to be unintentional because the types 'Record' and 'undefined' have no overlap. +spreadOfObjectLiteralAssignableToIndexSignature.ts(7,30): error TS2367: This comparison appears to be unintentional because the types 'Record' and 'undefined' have no overlap. +spreadOfObjectLiteralAssignableToIndexSignature.ts(11,38): error TS2367: This comparison appears to be unintentional because the types 'Record' and 'undefined' have no overlap. +spreadOfObjectLiteralAssignableToIndexSignature.ts(13,38): error TS2367: This comparison appears to be unintentional because the types 'Record' and 'undefined' have no overlap. + + +==== spreadOfObjectLiteralAssignableToIndexSignature.ts (4 errors) ==== + const foo: Record = {} // OK + + interface RecordOfRecords extends Record {} + const recordOfRecords: RecordOfRecords = {} + recordOfRecords.propA = {...(foo !== undefined ? {foo} : {})} // OK + ~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'Record' and 'undefined' have no overlap. + recordOfRecords.propB = {...(foo && {foo})} // OK + recordOfRecords.propC = {...(foo !== undefined && {foo})} // error'd in 3.7 beta, should be OK + ~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'Record' and 'undefined' have no overlap. + + interface RecordOfRecordsOrEmpty extends Record {} + const recordsOfRecordsOrEmpty: RecordOfRecordsOrEmpty = {} + recordsOfRecordsOrEmpty.propA = {...(foo !== undefined ? {foo} : {})} // OK + ~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'Record' and 'undefined' have no overlap. + recordsOfRecordsOrEmpty.propB = {...(foo && {foo})} // OK + recordsOfRecordsOrEmpty.propC = {...(foo !== undefined && {foo})} // OK + ~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'Record' and 'undefined' have no overlap. \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty3.errors.txt b/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty3.errors.txt new file mode 100644 index 0000000000000..2413c065c2149 --- /dev/null +++ b/tests/baselines/reference/typeGuardNarrowsIndexedAccessOfKnownProperty3.errors.txt @@ -0,0 +1,15 @@ +typeGuardNarrowsIndexedAccessOfKnownProperty3.ts(6,5): error TS2367: This comparison appears to be unintentional because the types '(number | undefined)[]' and 'undefined' have no overlap. + + +==== typeGuardNarrowsIndexedAccessOfKnownProperty3.ts (1 errors) ==== + type Foo = (number | undefined)[] | undefined; + + const foo: Foo = [1, 2, 3]; + const index = 1; + + if (foo !== undefined && foo[index] !== undefined && foo[index] >= 0) { + ~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types '(number | undefined)[]' and 'undefined' have no overlap. + foo[index] // number + } + \ No newline at end of file diff --git a/tests/baselines/reference/uncalledFunctionChecksInConditional2.errors.txt b/tests/baselines/reference/uncalledFunctionChecksInConditional2.errors.txt index 54feef1029a7d..ab4377a3e27a8 100644 --- a/tests/baselines/reference/uncalledFunctionChecksInConditional2.errors.txt +++ b/tests/baselines/reference/uncalledFunctionChecksInConditional2.errors.txt @@ -1,9 +1,10 @@ uncalledFunctionChecksInConditional2.ts(20,5): error TS2774: This condition will always return true since this function is always defined. Did you mean to call it instead? uncalledFunctionChecksInConditional2.ts(30,7): error TS2774: This condition will always return true since this function is always defined. Did you mean to call it instead? uncalledFunctionChecksInConditional2.ts(49,5): error TS2774: This condition will always return true since this function is always defined. Did you mean to call it instead? +uncalledFunctionChecksInConditional2.ts(63,7): error TS2367: This comparison appears to be unintentional because the types 'boolean' and 'undefined' have no overlap. -==== uncalledFunctionChecksInConditional2.ts (3 errors) ==== +==== uncalledFunctionChecksInConditional2.ts (4 errors) ==== { const perf = window.performance @@ -73,6 +74,8 @@ uncalledFunctionChecksInConditional2.ts(49,5): error TS2774: This condition will let _isMobile: boolean; function isMobile() { if (_isMobile === undefined) { + ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'boolean' and 'undefined' have no overlap. const isMobileMatch = typeof window !== 'undefined' && window.matchMedia && // no error diff --git a/tests/baselines/reference/unknownControlFlow.errors.txt b/tests/baselines/reference/unknownControlFlow.errors.txt index e8f4f198a505a..527a47d6a8d96 100644 --- a/tests/baselines/reference/unknownControlFlow.errors.txt +++ b/tests/baselines/reference/unknownControlFlow.errors.txt @@ -1,4 +1,6 @@ unknownControlFlow.ts(18,9): error TS2322: Type 'unknown' is not assignable to type '{}'. +unknownControlFlow.ts(136,9): error TS2367: This comparison appears to be unintentional because the types 'T' and 'null' have no overlap. +unknownControlFlow.ts(142,28): error TS2367: This comparison appears to be unintentional because the types 'T & {}' and 'null' have no overlap. unknownControlFlow.ts(283,5): error TS2536: Type 'keyof (T & {})' cannot be used to index type 'T'. unknownControlFlow.ts(290,11): error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. unknownControlFlow.ts(291,5): error TS2345: Argument of type 'null' is not assignable to parameter of type 'never'. @@ -7,7 +9,7 @@ unknownControlFlow.ts(323,9): error TS2367: This comparison appears to be uninte unknownControlFlow.ts(341,9): error TS2367: This comparison appears to be unintentional because the types 'T' and 'number' have no overlap. -==== unknownControlFlow.ts (7 errors) ==== +==== unknownControlFlow.ts (9 errors) ==== type T01 = {} & string; // {} & string type T02 = {} & 'a'; // 'a' type T03 = {} & object; // object @@ -146,12 +148,16 @@ unknownControlFlow.ts(341,9): error TS2367: This comparison appears to be uninte x; // T } if (x !== null) { + ~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'T' and 'null' have no overlap. x; // T } else { x; // T } if (x !== undefined && x !== null) { + ~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'T & {}' and 'null' have no overlap. x; // T & {} } else { diff --git a/tests/cases/compiler/nullableAndOtherTypesEquality1.ts b/tests/cases/compiler/nullableAndOtherTypesEquality1.ts new file mode 100644 index 0000000000000..a6d4b8e33e454 --- /dev/null +++ b/tests/cases/compiler/nullableAndOtherTypesEquality1.ts @@ -0,0 +1,79 @@ +// @strict: true +// @strictNullChecks: true, false +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/11920 + +if (null === undefined) { +} +if (null == undefined) { +} + +declare const str: string; +declare const strOrNull: string | null; +declare const strOrUndef: string | undefined; +declare const strOrNullUndef: string | null | undefined; + +if (str === null) { +} +if (str === undefined) { +} +if (str == null) { +} +if (str == undefined) { +} + +switch (str) { + case null: + case undefined: + case "a": + default: +} + +if (strOrNull === null) { +} +if (strOrNull === undefined) { +} +if (strOrNull == null) { +} +if (strOrNull == undefined) { +} + +switch (strOrNull) { + case null: + case undefined: + case "a": + default: +} + +if (strOrUndef === null) { +} +if (strOrUndef === undefined) { +} +if (strOrUndef == null) { +} +if (strOrUndef == undefined) { +} + +switch (strOrUndef) { + case null: + case undefined: + case "a": + default: +} + +if (strOrNullUndef === null) { +} +if (strOrNullUndef === undefined) { +} +if (strOrNullUndef == null) { +} +if (strOrNullUndef == undefined) { +} + +switch (strOrNullUndef) { + case null: + case undefined: + case "a": + default: +} From b1f062dcd71e1fb5e4aaff404cfc9016245611fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 8 Aug 2024 12:47:04 +0200 Subject: [PATCH 2/2] add extra test --- ...sEquality1(strictnullchecks=false).symbols | 17 ++++++++ ...pesEquality1(strictnullchecks=false).types | 41 +++++++++++++++++++ ...quality1(strictnullchecks=true).errors.txt | 23 ++++++++++- ...esEquality1(strictnullchecks=true).symbols | 17 ++++++++ ...ypesEquality1(strictnullchecks=true).types | 41 +++++++++++++++++++ .../nullableAndOtherTypesEquality1.ts | 9 ++++ 6 files changed, 147 insertions(+), 1 deletion(-) diff --git a/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=false).symbols b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=false).symbols index d3015e2b719de..cf6031a32f6f7 100644 --- a/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=false).symbols +++ b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=false).symbols @@ -126,3 +126,20 @@ switch (strOrNullUndef) { default: } +if (typeof str === undefined) { +>str : Symbol(str, Decl(nullableAndOtherTypesEquality1.ts, 7, 13)) +>undefined : Symbol(undefined) +} +if (typeof strOrNull === undefined) { +>strOrNull : Symbol(strOrNull, Decl(nullableAndOtherTypesEquality1.ts, 8, 13)) +>undefined : Symbol(undefined) +} +if (typeof strOrUndef === undefined) { +>strOrUndef : Symbol(strOrUndef, Decl(nullableAndOtherTypesEquality1.ts, 9, 13)) +>undefined : Symbol(undefined) +} +if (typeof strOrNullUndef === undefined) { +>strOrNullUndef : Symbol(strOrNullUndef, Decl(nullableAndOtherTypesEquality1.ts, 10, 13)) +>undefined : Symbol(undefined) +} + diff --git a/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=false).types b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=false).types index 65e463f832246..be84be0fa4667 100644 --- a/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=false).types +++ b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=false).types @@ -212,3 +212,44 @@ switch (strOrNullUndef) { default: } +if (typeof str === undefined) { +>typeof str === undefined : boolean +> : ^^^^^^^ +>typeof str : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>str : string +> : ^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} +if (typeof strOrNull === undefined) { +>typeof strOrNull === undefined : boolean +> : ^^^^^^^ +>typeof strOrNull : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>strOrNull : string +> : ^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} +if (typeof strOrUndef === undefined) { +>typeof strOrUndef === undefined : boolean +> : ^^^^^^^ +>typeof strOrUndef : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>strOrUndef : string +> : ^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} +if (typeof strOrNullUndef === undefined) { +>typeof strOrNullUndef === undefined : boolean +> : ^^^^^^^ +>typeof strOrNullUndef : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>strOrNullUndef : string +> : ^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} + diff --git a/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).errors.txt b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).errors.txt index cbb6596ec7420..155d8df1333d2 100644 --- a/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).errors.txt +++ b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).errors.txt @@ -7,9 +7,13 @@ nullableAndOtherTypesEquality1.ts(31,5): error TS2367: This comparison appears t nullableAndOtherTypesEquality1.ts(40,8): error TS2678: Type 'undefined' is not comparable to type 'string | null'. nullableAndOtherTypesEquality1.ts(45,5): error TS2367: This comparison appears to be unintentional because the types 'string | undefined' and 'null' have no overlap. nullableAndOtherTypesEquality1.ts(55,8): error TS2678: Type 'null' is not comparable to type 'string | undefined'. +nullableAndOtherTypesEquality1.ts(77,5): error TS2367: This comparison appears to be unintentional because the types 'string' and 'undefined' have no overlap. +nullableAndOtherTypesEquality1.ts(79,5): error TS2367: This comparison appears to be unintentional because the types 'string' and 'undefined' have no overlap. +nullableAndOtherTypesEquality1.ts(81,5): error TS2367: This comparison appears to be unintentional because the types 'string' and 'undefined' have no overlap. +nullableAndOtherTypesEquality1.ts(83,5): error TS2367: This comparison appears to be unintentional because the types 'string' and 'undefined' have no overlap. -==== nullableAndOtherTypesEquality1.ts (9 errors) ==== +==== nullableAndOtherTypesEquality1.ts (13 errors) ==== // https://github.com/microsoft/TypeScript/issues/11920 if (null === undefined) { @@ -103,4 +107,21 @@ nullableAndOtherTypesEquality1.ts(55,8): error TS2678: Type 'null' is not compar case "a": default: } + + if (typeof str === undefined) { + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string' and 'undefined' have no overlap. + } + if (typeof strOrNull === undefined) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string' and 'undefined' have no overlap. + } + if (typeof strOrUndef === undefined) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string' and 'undefined' have no overlap. + } + if (typeof strOrNullUndef === undefined) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'string' and 'undefined' have no overlap. + } \ No newline at end of file diff --git a/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).symbols b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).symbols index d3015e2b719de..cf6031a32f6f7 100644 --- a/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).symbols +++ b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).symbols @@ -126,3 +126,20 @@ switch (strOrNullUndef) { default: } +if (typeof str === undefined) { +>str : Symbol(str, Decl(nullableAndOtherTypesEquality1.ts, 7, 13)) +>undefined : Symbol(undefined) +} +if (typeof strOrNull === undefined) { +>strOrNull : Symbol(strOrNull, Decl(nullableAndOtherTypesEquality1.ts, 8, 13)) +>undefined : Symbol(undefined) +} +if (typeof strOrUndef === undefined) { +>strOrUndef : Symbol(strOrUndef, Decl(nullableAndOtherTypesEquality1.ts, 9, 13)) +>undefined : Symbol(undefined) +} +if (typeof strOrNullUndef === undefined) { +>strOrNullUndef : Symbol(strOrNullUndef, Decl(nullableAndOtherTypesEquality1.ts, 10, 13)) +>undefined : Symbol(undefined) +} + diff --git a/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).types b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).types index 40044341ab0e0..0431d20f1c35a 100644 --- a/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).types +++ b/tests/baselines/reference/nullableAndOtherTypesEquality1(strictnullchecks=true).types @@ -212,3 +212,44 @@ switch (strOrNullUndef) { default: } +if (typeof str === undefined) { +>typeof str === undefined : boolean +> : ^^^^^^^ +>typeof str : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>str : string +> : ^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} +if (typeof strOrNull === undefined) { +>typeof strOrNull === undefined : boolean +> : ^^^^^^^ +>typeof strOrNull : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>strOrNull : string | null +> : ^^^^^^^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} +if (typeof strOrUndef === undefined) { +>typeof strOrUndef === undefined : boolean +> : ^^^^^^^ +>typeof strOrUndef : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>strOrUndef : string | undefined +> : ^^^^^^^^^^^^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} +if (typeof strOrNullUndef === undefined) { +>typeof strOrNullUndef === undefined : boolean +> : ^^^^^^^ +>typeof strOrNullUndef : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>strOrNullUndef : string | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +} + diff --git a/tests/cases/compiler/nullableAndOtherTypesEquality1.ts b/tests/cases/compiler/nullableAndOtherTypesEquality1.ts index a6d4b8e33e454..df49b56071b7f 100644 --- a/tests/cases/compiler/nullableAndOtherTypesEquality1.ts +++ b/tests/cases/compiler/nullableAndOtherTypesEquality1.ts @@ -77,3 +77,12 @@ switch (strOrNullUndef) { case "a": default: } + +if (typeof str === undefined) { +} +if (typeof strOrNull === undefined) { +} +if (typeof strOrUndef === undefined) { +} +if (typeof strOrNullUndef === undefined) { +}