Skip to content

Commit

Permalink
Fixed an issue with missingType narrowing by case undefined in de…
Browse files Browse the repository at this point in the history
…fault cases (#58001)
  • Loading branch information
Andarist authored May 1, 2024
1 parent 33b1561 commit f01cae8
Show file tree
Hide file tree
Showing 10 changed files with 837 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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, --, --))
}

Original file line number Diff line number Diff line change
@@ -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"
> : ^^^^^^^^^^^^^^^^^^^^^^^^
}

Original file line number Diff line number Diff line change
@@ -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, --, --))
}

Loading

0 comments on commit f01cae8

Please sign in to comment.