Fixed issue where non null assertion caused getFlowTypeOfReference to return the declared type if the type was already narrowed to never. (#35863)

This was caused by the fact that getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull) will return never both if resultType was already never and if resultType does not contain undefined or null. In the latter case returning the declaring type is correct, in the former case this causes something narrowed to never to still be typed as the original declared type.
This commit is contained in:
Titian Cernicova-Dragomir 2021-03-11 17:33:33 +02:00 committed by GitHub
parent 3d6650eb4f
commit 71661b932a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 107 additions and 4 deletions

View File

@ -22447,7 +22447,7 @@ namespace ts {
// on empty arrays are possible without implicit any errors and new element types can be inferred without
// type mismatch errors.
const resultType = getObjectFlags(evolvedType) & ObjectFlags.EvolvingArray && isEvolvingArrayOperationTarget(reference) ? autoArrayType : finalizeEvolvingArrayType(evolvedType);
if (resultType === unreachableNeverType || reference.parent && reference.parent.kind === SyntaxKind.NonNullExpression && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) {
if (resultType === unreachableNeverType || reference.parent && reference.parent.kind === SyntaxKind.NonNullExpression && !(resultType.flags & TypeFlags.Never) && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) {
return declaredType;
}
return resultType;

View File

@ -1,8 +1,9 @@
tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(7,9): error TS7027: Unreachable code detected.
tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(235,5): error TS2367: This condition will always return 'false' since the types 'keyof O' and '"c"' have no overlap.
tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(247,10): error TS2339: Property 'kind' does not exist on type 'never'.
==== tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts (2 errors) ====
==== tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts (3 errors) ====
function f1(x: 1 | 2): string {
if (!!true) {
switch (x) {
@ -244,4 +245,17 @@ tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(235,5): error
!!! error TS2367: This condition will always return 'false' since the types 'keyof O' and '"c"' have no overlap.
return o[k];
}
// Repro from #35431
type A = { kind: "abc" } | { kind: "def" };
function f35431(a: A) {
switch (a.kind) {
case "abc":
case "def": return;
default:
a!.kind; // Error expected
~~~~
!!! error TS2339: Property 'kind' does not exist on type 'never'.
}
}

View File

@ -236,7 +236,18 @@ function ff(o: O, k: K) {
k === 'c'; // Error
return o[k];
}
// Repro from #35431
type A = { kind: "abc" } | { kind: "def" };
function f35431(a: A) {
switch (a.kind) {
case "abc":
case "def": return;
default:
a!.kind; // Error expected
}
}
//// [exhaustiveSwitchStatements1.js]
"use strict";
@ -453,6 +464,14 @@ function ff(o, k) {
k === 'c'; // Error
return o[k];
}
function f35431(a) {
switch (a.kind) {
case "abc":
case "def": return;
default:
a.kind; // Error expected
}
}
//// [exhaustiveSwitchStatements1.d.ts]
@ -524,3 +543,9 @@ declare type O = {
};
declare type K = keyof O | 'c';
declare function ff(o: O, k: K): number;
declare type A = {
kind: "abc";
} | {
kind: "def";
};
declare function f35431(a: A): void;

View File

@ -603,3 +603,26 @@ function ff(o: O, k: K) {
>k : Symbol(k, Decl(exhaustiveSwitchStatements1.ts, 229, 17))
}
// Repro from #35431
type A = { kind: "abc" } | { kind: "def" };
>A : Symbol(A, Decl(exhaustiveSwitchStatements1.ts, 236, 1))
>kind : Symbol(kind, Decl(exhaustiveSwitchStatements1.ts, 239, 10))
>kind : Symbol(kind, Decl(exhaustiveSwitchStatements1.ts, 239, 28))
function f35431(a: A) {
>f35431 : Symbol(f35431, Decl(exhaustiveSwitchStatements1.ts, 239, 43))
>a : Symbol(a, Decl(exhaustiveSwitchStatements1.ts, 241, 16))
>A : Symbol(A, Decl(exhaustiveSwitchStatements1.ts, 236, 1))
switch (a.kind) {
>a.kind : Symbol(kind, Decl(exhaustiveSwitchStatements1.ts, 239, 10), Decl(exhaustiveSwitchStatements1.ts, 239, 28))
>a : Symbol(a, Decl(exhaustiveSwitchStatements1.ts, 241, 16))
>kind : Symbol(kind, Decl(exhaustiveSwitchStatements1.ts, 239, 10), Decl(exhaustiveSwitchStatements1.ts, 239, 28))
case "abc":
case "def": return;
default:
a!.kind; // Error expected
>a : Symbol(a, Decl(exhaustiveSwitchStatements1.ts, 241, 16))
}
}

View File

@ -704,3 +704,32 @@ function ff(o: O, k: K) {
>k : keyof O
}
// Repro from #35431
type A = { kind: "abc" } | { kind: "def" };
>A : A
>kind : "abc"
>kind : "def"
function f35431(a: A) {
>f35431 : (a: A) => void
>a : A
switch (a.kind) {
>a.kind : "abc" | "def"
>a : A
>kind : "abc" | "def"
case "abc":
>"abc" : "abc"
case "def": return;
>"def" : "def"
default:
a!.kind; // Error expected
>a!.kind : any
>a! : never
>a : never
>kind : any
}
}

View File

@ -239,3 +239,15 @@ function ff(o: O, k: K) {
k === 'c'; // Error
return o[k];
}
// Repro from #35431
type A = { kind: "abc" } | { kind: "def" };
function f35431(a: A) {
switch (a.kind) {
case "abc":
case "def": return;
default:
a!.kind; // Error expected
}
}