From f01cae8893922dde8534edbcae2a0fd54bc19f57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 1 May 2024 17:57:42 +0200 Subject: [PATCH] Fixed an issue with `missingType` narrowing by `case undefined` in default cases (#58001) --- src/compiler/checker.ts | 2 +- ...se,nouncheckedindexedaccess=false).symbols | 75 +++++++++++ ...alse,nouncheckedindexedaccess=false).types | 124 ++++++++++++++++++ ...lse,nouncheckedindexedaccess=true).symbols | 75 +++++++++++ ...false,nouncheckedindexedaccess=true).types | 124 ++++++++++++++++++ ...ue,nouncheckedindexedaccess=false).symbols | 75 +++++++++++ ...true,nouncheckedindexedaccess=false).types | 124 ++++++++++++++++++ ...rue,nouncheckedindexedaccess=true).symbols | 75 +++++++++++ ...=true,nouncheckedindexedaccess=true).types | 124 ++++++++++++++++++ ...arrowBySwitchDiscriminantUndefinedCase1.ts | 40 ++++++ 10 files changed, 837 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=false).symbols create mode 100644 tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=false).types create mode 100644 tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=true).symbols create mode 100644 tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=true).types create mode 100644 tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=false).symbols create mode 100644 tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=false).types create mode 100644 tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=true).symbols create mode 100644 tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=true).types create mode 100644 tests/cases/compiler/narrowBySwitchDiscriminantUndefinedCase1.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 51b3a8a6c50..027007fb15b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -28543,7 +28543,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!hasDefaultClause) { return caseType; } - const defaultType = filterType(type, t => !(isUnitLikeType(t) && contains(switchTypes, getRegularTypeOfLiteralType(extractUnitType(t))))); + const defaultType = filterType(type, t => !(isUnitLikeType(t) && contains(switchTypes, t.flags & TypeFlags.Undefined ? undefinedType : getRegularTypeOfLiteralType(extractUnitType(t))))); return caseType.flags & TypeFlags.Never ? defaultType : getUnionType([caseType, defaultType]); } diff --git a/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=false).symbols b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=false).symbols new file mode 100644 index 00000000000..67e0d371e9f --- /dev/null +++ b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=false).symbols @@ -0,0 +1,75 @@ +//// [tests/cases/compiler/narrowBySwitchDiscriminantUndefinedCase1.ts] //// + +=== narrowBySwitchDiscriminantUndefinedCase1.ts === +// https://github.com/microsoft/TypeScript/issues/57999 + +interface A { +>A : Symbol(A, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 0, 0)) + + optionalProp?: "hello"; +>optionalProp : Symbol(A.optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 2, 13)) +} + +function func(arg: A) { +>func : Symbol(func, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 4, 1)) +>arg : Symbol(arg, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 6, 14)) +>A : Symbol(A, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 0, 0)) + + const { optionalProp } = arg; +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9)) +>arg : Symbol(arg, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 6, 14)) + + switch (optionalProp) { +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9)) + + case undefined: +>undefined : Symbol(undefined) + + return undefined; +>undefined : Symbol(undefined) + + case "hello": + return "hello"; + default: + assertUnreachable(optionalProp); +>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1)) +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9)) + } +} + +function func2() { +>func2 : Symbol(func2, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 17, 1)) + + const optionalProp = ["hello" as const][Math.random()]; +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7)) +>const : Symbol(const) +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) + + switch (optionalProp) { +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7)) + + case undefined: +>undefined : Symbol(undefined) + + return undefined; +>undefined : Symbol(undefined) + + case "hello": + return "hello"; + default: + assertUnreachable(optionalProp); +>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1)) +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7)) + } +} + +function assertUnreachable(_: never): never { +>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1)) +>_ : Symbol(_, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 32, 27)) + + throw new Error("Unreachable path taken"); +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +} + diff --git a/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=false).types b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=false).types new file mode 100644 index 00000000000..cbb0a818357 --- /dev/null +++ b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=false).types @@ -0,0 +1,124 @@ +//// [tests/cases/compiler/narrowBySwitchDiscriminantUndefinedCase1.ts] //// + +=== narrowBySwitchDiscriminantUndefinedCase1.ts === +// https://github.com/microsoft/TypeScript/issues/57999 + +interface A { + optionalProp?: "hello"; +>optionalProp : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ +} + +function func(arg: A) { +>func : (arg: A) => "hello" | undefined +> : ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>arg : A +> : ^ + + const { optionalProp } = arg; +>optionalProp : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ +>arg : A +> : ^ + + switch (optionalProp) { +>optionalProp : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ + + case undefined: +>undefined : undefined +> : ^^^^^^^^^ + + return undefined; +>undefined : undefined +> : ^^^^^^^^^ + + case "hello": +>"hello" : "hello" +> : ^^^^^^^ + + return "hello"; +>"hello" : "hello" +> : ^^^^^^^ + + default: + assertUnreachable(optionalProp); +>assertUnreachable(optionalProp) : never +> : ^^^^^ +>assertUnreachable : (_: never) => never +> : ^^^^^^^^^^^^^^^^^^^ +>optionalProp : never +> : ^^^^^ + } +} + +function func2() { +>func2 : () => "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + + const optionalProp = ["hello" as const][Math.random()]; +>optionalProp : "hello" +> : ^^^^^^^ +>["hello" as const][Math.random()] : "hello" +> : ^^^^^^^ +>["hello" as const] : "hello"[] +> : ^^^^^^^^^ +>"hello" as const : "hello" +> : ^^^^^^^ +>"hello" : "hello" +> : ^^^^^^^ +>Math.random() : number +> : ^^^^^^ +>Math.random : () => number +> : ^^^^^^^^^^^^ +>Math : Math +> : ^^^^ +>random : () => number +> : ^^^^^^^^^^^^ + + switch (optionalProp) { +>optionalProp : "hello" +> : ^^^^^^^ + + case undefined: +>undefined : undefined +> : ^^^^^^^^^ + + return undefined; +>undefined : undefined +> : ^^^^^^^^^ + + case "hello": +>"hello" : "hello" +> : ^^^^^^^ + + return "hello"; +>"hello" : "hello" +> : ^^^^^^^ + + default: + assertUnreachable(optionalProp); +>assertUnreachable(optionalProp) : never +> : ^^^^^ +>assertUnreachable : (_: never) => never +> : ^^^^^^^^^^^^^^^^^^^ +>optionalProp : never +> : ^^^^^ + } +} + +function assertUnreachable(_: never): never { +>assertUnreachable : (_: never) => never +> : ^^^^ ^^^^^ +>_ : never +> : ^^^^^ + + throw new Error("Unreachable path taken"); +>new Error("Unreachable path taken") : Error +> : ^^^^^ +>Error : ErrorConstructor +> : ^^^^^^^^^^^^^^^^ +>"Unreachable path taken" : "Unreachable path taken" +> : ^^^^^^^^^^^^^^^^^^^^^^^^ +} + diff --git a/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=true).symbols b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=true).symbols new file mode 100644 index 00000000000..67e0d371e9f --- /dev/null +++ b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=true).symbols @@ -0,0 +1,75 @@ +//// [tests/cases/compiler/narrowBySwitchDiscriminantUndefinedCase1.ts] //// + +=== narrowBySwitchDiscriminantUndefinedCase1.ts === +// https://github.com/microsoft/TypeScript/issues/57999 + +interface A { +>A : Symbol(A, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 0, 0)) + + optionalProp?: "hello"; +>optionalProp : Symbol(A.optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 2, 13)) +} + +function func(arg: A) { +>func : Symbol(func, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 4, 1)) +>arg : Symbol(arg, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 6, 14)) +>A : Symbol(A, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 0, 0)) + + const { optionalProp } = arg; +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9)) +>arg : Symbol(arg, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 6, 14)) + + switch (optionalProp) { +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9)) + + case undefined: +>undefined : Symbol(undefined) + + return undefined; +>undefined : Symbol(undefined) + + case "hello": + return "hello"; + default: + assertUnreachable(optionalProp); +>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1)) +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9)) + } +} + +function func2() { +>func2 : Symbol(func2, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 17, 1)) + + const optionalProp = ["hello" as const][Math.random()]; +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7)) +>const : Symbol(const) +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) + + switch (optionalProp) { +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7)) + + case undefined: +>undefined : Symbol(undefined) + + return undefined; +>undefined : Symbol(undefined) + + case "hello": + return "hello"; + default: + assertUnreachable(optionalProp); +>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1)) +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7)) + } +} + +function assertUnreachable(_: never): never { +>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1)) +>_ : Symbol(_, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 32, 27)) + + throw new Error("Unreachable path taken"); +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +} + diff --git a/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=true).types b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=true).types new file mode 100644 index 00000000000..7ed816b17a3 --- /dev/null +++ b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=false,nouncheckedindexedaccess=true).types @@ -0,0 +1,124 @@ +//// [tests/cases/compiler/narrowBySwitchDiscriminantUndefinedCase1.ts] //// + +=== narrowBySwitchDiscriminantUndefinedCase1.ts === +// https://github.com/microsoft/TypeScript/issues/57999 + +interface A { + optionalProp?: "hello"; +>optionalProp : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ +} + +function func(arg: A) { +>func : (arg: A) => "hello" | undefined +> : ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>arg : A +> : ^ + + const { optionalProp } = arg; +>optionalProp : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ +>arg : A +> : ^ + + switch (optionalProp) { +>optionalProp : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ + + case undefined: +>undefined : undefined +> : ^^^^^^^^^ + + return undefined; +>undefined : undefined +> : ^^^^^^^^^ + + case "hello": +>"hello" : "hello" +> : ^^^^^^^ + + return "hello"; +>"hello" : "hello" +> : ^^^^^^^ + + default: + assertUnreachable(optionalProp); +>assertUnreachable(optionalProp) : never +> : ^^^^^ +>assertUnreachable : (_: never) => never +> : ^^^^^^^^^^^^^^^^^^^ +>optionalProp : never +> : ^^^^^ + } +} + +function func2() { +>func2 : () => "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + + const optionalProp = ["hello" as const][Math.random()]; +>optionalProp : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ +>["hello" as const][Math.random()] : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ +>["hello" as const] : "hello"[] +> : ^^^^^^^^^ +>"hello" as const : "hello" +> : ^^^^^^^ +>"hello" : "hello" +> : ^^^^^^^ +>Math.random() : number +> : ^^^^^^ +>Math.random : () => number +> : ^^^^^^^^^^^^ +>Math : Math +> : ^^^^ +>random : () => number +> : ^^^^^^^^^^^^ + + switch (optionalProp) { +>optionalProp : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ + + case undefined: +>undefined : undefined +> : ^^^^^^^^^ + + return undefined; +>undefined : undefined +> : ^^^^^^^^^ + + case "hello": +>"hello" : "hello" +> : ^^^^^^^ + + return "hello"; +>"hello" : "hello" +> : ^^^^^^^ + + default: + assertUnreachable(optionalProp); +>assertUnreachable(optionalProp) : never +> : ^^^^^ +>assertUnreachable : (_: never) => never +> : ^^^^^^^^^^^^^^^^^^^ +>optionalProp : never +> : ^^^^^ + } +} + +function assertUnreachable(_: never): never { +>assertUnreachable : (_: never) => never +> : ^^^^ ^^^^^ +>_ : never +> : ^^^^^ + + throw new Error("Unreachable path taken"); +>new Error("Unreachable path taken") : Error +> : ^^^^^ +>Error : ErrorConstructor +> : ^^^^^^^^^^^^^^^^ +>"Unreachable path taken" : "Unreachable path taken" +> : ^^^^^^^^^^^^^^^^^^^^^^^^ +} + diff --git a/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=false).symbols b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=false).symbols new file mode 100644 index 00000000000..67e0d371e9f --- /dev/null +++ b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=false).symbols @@ -0,0 +1,75 @@ +//// [tests/cases/compiler/narrowBySwitchDiscriminantUndefinedCase1.ts] //// + +=== narrowBySwitchDiscriminantUndefinedCase1.ts === +// https://github.com/microsoft/TypeScript/issues/57999 + +interface A { +>A : Symbol(A, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 0, 0)) + + optionalProp?: "hello"; +>optionalProp : Symbol(A.optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 2, 13)) +} + +function func(arg: A) { +>func : Symbol(func, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 4, 1)) +>arg : Symbol(arg, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 6, 14)) +>A : Symbol(A, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 0, 0)) + + const { optionalProp } = arg; +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9)) +>arg : Symbol(arg, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 6, 14)) + + switch (optionalProp) { +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9)) + + case undefined: +>undefined : Symbol(undefined) + + return undefined; +>undefined : Symbol(undefined) + + case "hello": + return "hello"; + default: + assertUnreachable(optionalProp); +>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1)) +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9)) + } +} + +function func2() { +>func2 : Symbol(func2, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 17, 1)) + + const optionalProp = ["hello" as const][Math.random()]; +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7)) +>const : Symbol(const) +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) + + switch (optionalProp) { +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7)) + + case undefined: +>undefined : Symbol(undefined) + + return undefined; +>undefined : Symbol(undefined) + + case "hello": + return "hello"; + default: + assertUnreachable(optionalProp); +>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1)) +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7)) + } +} + +function assertUnreachable(_: never): never { +>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1)) +>_ : Symbol(_, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 32, 27)) + + throw new Error("Unreachable path taken"); +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +} + diff --git a/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=false).types b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=false).types new file mode 100644 index 00000000000..cbb0a818357 --- /dev/null +++ b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=false).types @@ -0,0 +1,124 @@ +//// [tests/cases/compiler/narrowBySwitchDiscriminantUndefinedCase1.ts] //// + +=== narrowBySwitchDiscriminantUndefinedCase1.ts === +// https://github.com/microsoft/TypeScript/issues/57999 + +interface A { + optionalProp?: "hello"; +>optionalProp : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ +} + +function func(arg: A) { +>func : (arg: A) => "hello" | undefined +> : ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>arg : A +> : ^ + + const { optionalProp } = arg; +>optionalProp : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ +>arg : A +> : ^ + + switch (optionalProp) { +>optionalProp : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ + + case undefined: +>undefined : undefined +> : ^^^^^^^^^ + + return undefined; +>undefined : undefined +> : ^^^^^^^^^ + + case "hello": +>"hello" : "hello" +> : ^^^^^^^ + + return "hello"; +>"hello" : "hello" +> : ^^^^^^^ + + default: + assertUnreachable(optionalProp); +>assertUnreachable(optionalProp) : never +> : ^^^^^ +>assertUnreachable : (_: never) => never +> : ^^^^^^^^^^^^^^^^^^^ +>optionalProp : never +> : ^^^^^ + } +} + +function func2() { +>func2 : () => "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + + const optionalProp = ["hello" as const][Math.random()]; +>optionalProp : "hello" +> : ^^^^^^^ +>["hello" as const][Math.random()] : "hello" +> : ^^^^^^^ +>["hello" as const] : "hello"[] +> : ^^^^^^^^^ +>"hello" as const : "hello" +> : ^^^^^^^ +>"hello" : "hello" +> : ^^^^^^^ +>Math.random() : number +> : ^^^^^^ +>Math.random : () => number +> : ^^^^^^^^^^^^ +>Math : Math +> : ^^^^ +>random : () => number +> : ^^^^^^^^^^^^ + + switch (optionalProp) { +>optionalProp : "hello" +> : ^^^^^^^ + + case undefined: +>undefined : undefined +> : ^^^^^^^^^ + + return undefined; +>undefined : undefined +> : ^^^^^^^^^ + + case "hello": +>"hello" : "hello" +> : ^^^^^^^ + + return "hello"; +>"hello" : "hello" +> : ^^^^^^^ + + default: + assertUnreachable(optionalProp); +>assertUnreachable(optionalProp) : never +> : ^^^^^ +>assertUnreachable : (_: never) => never +> : ^^^^^^^^^^^^^^^^^^^ +>optionalProp : never +> : ^^^^^ + } +} + +function assertUnreachable(_: never): never { +>assertUnreachable : (_: never) => never +> : ^^^^ ^^^^^ +>_ : never +> : ^^^^^ + + throw new Error("Unreachable path taken"); +>new Error("Unreachable path taken") : Error +> : ^^^^^ +>Error : ErrorConstructor +> : ^^^^^^^^^^^^^^^^ +>"Unreachable path taken" : "Unreachable path taken" +> : ^^^^^^^^^^^^^^^^^^^^^^^^ +} + diff --git a/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=true).symbols b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=true).symbols new file mode 100644 index 00000000000..67e0d371e9f --- /dev/null +++ b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=true).symbols @@ -0,0 +1,75 @@ +//// [tests/cases/compiler/narrowBySwitchDiscriminantUndefinedCase1.ts] //// + +=== narrowBySwitchDiscriminantUndefinedCase1.ts === +// https://github.com/microsoft/TypeScript/issues/57999 + +interface A { +>A : Symbol(A, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 0, 0)) + + optionalProp?: "hello"; +>optionalProp : Symbol(A.optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 2, 13)) +} + +function func(arg: A) { +>func : Symbol(func, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 4, 1)) +>arg : Symbol(arg, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 6, 14)) +>A : Symbol(A, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 0, 0)) + + const { optionalProp } = arg; +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9)) +>arg : Symbol(arg, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 6, 14)) + + switch (optionalProp) { +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9)) + + case undefined: +>undefined : Symbol(undefined) + + return undefined; +>undefined : Symbol(undefined) + + case "hello": + return "hello"; + default: + assertUnreachable(optionalProp); +>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1)) +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 7, 9)) + } +} + +function func2() { +>func2 : Symbol(func2, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 17, 1)) + + const optionalProp = ["hello" as const][Math.random()]; +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7)) +>const : Symbol(const) +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) + + switch (optionalProp) { +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7)) + + case undefined: +>undefined : Symbol(undefined) + + return undefined; +>undefined : Symbol(undefined) + + case "hello": + return "hello"; + default: + assertUnreachable(optionalProp); +>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1)) +>optionalProp : Symbol(optionalProp, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 20, 7)) + } +} + +function assertUnreachable(_: never): never { +>assertUnreachable : Symbol(assertUnreachable, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 30, 1)) +>_ : Symbol(_, Decl(narrowBySwitchDiscriminantUndefinedCase1.ts, 32, 27)) + + throw new Error("Unreachable path taken"); +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +} + diff --git a/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=true).types b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=true).types new file mode 100644 index 00000000000..7ed816b17a3 --- /dev/null +++ b/tests/baselines/reference/narrowBySwitchDiscriminantUndefinedCase1(exactoptionalpropertytypes=true,nouncheckedindexedaccess=true).types @@ -0,0 +1,124 @@ +//// [tests/cases/compiler/narrowBySwitchDiscriminantUndefinedCase1.ts] //// + +=== narrowBySwitchDiscriminantUndefinedCase1.ts === +// https://github.com/microsoft/TypeScript/issues/57999 + +interface A { + optionalProp?: "hello"; +>optionalProp : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ +} + +function func(arg: A) { +>func : (arg: A) => "hello" | undefined +> : ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>arg : A +> : ^ + + const { optionalProp } = arg; +>optionalProp : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ +>arg : A +> : ^ + + switch (optionalProp) { +>optionalProp : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ + + case undefined: +>undefined : undefined +> : ^^^^^^^^^ + + return undefined; +>undefined : undefined +> : ^^^^^^^^^ + + case "hello": +>"hello" : "hello" +> : ^^^^^^^ + + return "hello"; +>"hello" : "hello" +> : ^^^^^^^ + + default: + assertUnreachable(optionalProp); +>assertUnreachable(optionalProp) : never +> : ^^^^^ +>assertUnreachable : (_: never) => never +> : ^^^^^^^^^^^^^^^^^^^ +>optionalProp : never +> : ^^^^^ + } +} + +function func2() { +>func2 : () => "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + + const optionalProp = ["hello" as const][Math.random()]; +>optionalProp : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ +>["hello" as const][Math.random()] : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ +>["hello" as const] : "hello"[] +> : ^^^^^^^^^ +>"hello" as const : "hello" +> : ^^^^^^^ +>"hello" : "hello" +> : ^^^^^^^ +>Math.random() : number +> : ^^^^^^ +>Math.random : () => number +> : ^^^^^^^^^^^^ +>Math : Math +> : ^^^^ +>random : () => number +> : ^^^^^^^^^^^^ + + switch (optionalProp) { +>optionalProp : "hello" | undefined +> : ^^^^^^^^^^^^^^^^^^^ + + case undefined: +>undefined : undefined +> : ^^^^^^^^^ + + return undefined; +>undefined : undefined +> : ^^^^^^^^^ + + case "hello": +>"hello" : "hello" +> : ^^^^^^^ + + return "hello"; +>"hello" : "hello" +> : ^^^^^^^ + + default: + assertUnreachable(optionalProp); +>assertUnreachable(optionalProp) : never +> : ^^^^^ +>assertUnreachable : (_: never) => never +> : ^^^^^^^^^^^^^^^^^^^ +>optionalProp : never +> : ^^^^^ + } +} + +function assertUnreachable(_: never): never { +>assertUnreachable : (_: never) => never +> : ^^^^ ^^^^^ +>_ : never +> : ^^^^^ + + throw new Error("Unreachable path taken"); +>new Error("Unreachable path taken") : Error +> : ^^^^^ +>Error : ErrorConstructor +> : ^^^^^^^^^^^^^^^^ +>"Unreachable path taken" : "Unreachable path taken" +> : ^^^^^^^^^^^^^^^^^^^^^^^^ +} + diff --git a/tests/cases/compiler/narrowBySwitchDiscriminantUndefinedCase1.ts b/tests/cases/compiler/narrowBySwitchDiscriminantUndefinedCase1.ts new file mode 100644 index 00000000000..256979f00ba --- /dev/null +++ b/tests/cases/compiler/narrowBySwitchDiscriminantUndefinedCase1.ts @@ -0,0 +1,40 @@ +// @strict: true +// @exactOptionalPropertyTypes: true, false +// @noUncheckedIndexedAccess: true, false +// @noEmit: true + +// 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: + return undefined; + case "hello": + return "hello"; + default: + assertUnreachable(optionalProp); + } +} + +function assertUnreachable(_: never): never { + throw new Error("Unreachable path taken"); +}