diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ef11dc904ea19..06ef246340252 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7662,7 +7662,7 @@ namespace ts { function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean, includeOuterFunctions: boolean) { let key: string; - if (!reference.flowNode || assumeInitialized && (declaredType.flags & TypeFlags.NotNarrowable)) { + if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) { return declaredType; } const initialType = assumeInitialized ? declaredType : addNullableKind(declaredType, TypeFlags.Undefined); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 026ee5da9604e..c7e14a1003108 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2218,13 +2218,7 @@ namespace ts { ObjectType = Class | Interface | Reference | Tuple | Anonymous, UnionOrIntersection = Union | Intersection, StructuredType = ObjectType | Union | Intersection, - - // 'NotNarrowable' types are types where narrowing reverts to the original type, rather than actually narrow. - // This is never really correct - you can _always_ narrow to an intersection with that type, _but_ we keep - // Void as the only non-narrowable type, since it's a non-value type construct (representing a lack of a value) - // and, generally speaking, narrowing `void` should fail in some way, as it is nonsensical. (`void` narrowing - // to `void & T`, in a structural sense, is just narrowing to T, which we wouldn't allow under normal rules) - NotNarrowable = Void, + Narrowable = Any | ObjectType | Union | TypeParameter, /* @internal */ RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral, /* @internal */ diff --git a/tests/baselines/reference/typeGuardNarrowsPrimitiveIntersection.js b/tests/baselines/reference/typeGuardNarrowsPrimitiveIntersection.js deleted file mode 100644 index a4cba6f4ab5c1..0000000000000 --- a/tests/baselines/reference/typeGuardNarrowsPrimitiveIntersection.js +++ /dev/null @@ -1,38 +0,0 @@ -//// [typeGuardNarrowsPrimitiveIntersection.ts] -type Tag = {__tag: any}; -declare function isNonBlank(value: string) : value is (string & Tag); -declare function doThis(value: string & Tag): void; -declare function doThat(value: string) : void; -let value: string; -if (isNonBlank(value)) { - doThis(value); -} else { - doThat(value); -} - - -const enum Tag2 {} -declare function isNonBlank2(value: string) : value is (string & Tag2); -declare function doThis2(value: string & Tag2): void; -declare function doThat2(value: string) : void; -if (isNonBlank2(value)) { - doThis2(value); -} else { - doThat2(value); -} - - -//// [typeGuardNarrowsPrimitiveIntersection.js] -var value; -if (isNonBlank(value)) { - doThis(value); -} -else { - doThat(value); -} -if (isNonBlank2(value)) { - doThis2(value); -} -else { - doThat2(value); -} diff --git a/tests/baselines/reference/typeGuardNarrowsPrimitiveIntersection.symbols b/tests/baselines/reference/typeGuardNarrowsPrimitiveIntersection.symbols deleted file mode 100644 index da507fb94c5dc..0000000000000 --- a/tests/baselines/reference/typeGuardNarrowsPrimitiveIntersection.symbols +++ /dev/null @@ -1,70 +0,0 @@ -=== tests/cases/conformance/expressions/typeGuards/typeGuardNarrowsPrimitiveIntersection.ts === -type Tag = {__tag: any}; ->Tag : Symbol(Tag, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 0, 0)) ->__tag : Symbol(__tag, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 0, 12)) - -declare function isNonBlank(value: string) : value is (string & Tag); ->isNonBlank : Symbol(isNonBlank, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 0, 24)) ->value : Symbol(value, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 1, 28)) ->value : Symbol(value, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 1, 28)) ->Tag : Symbol(Tag, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 0, 0)) - -declare function doThis(value: string & Tag): void; ->doThis : Symbol(doThis, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 1, 69)) ->value : Symbol(value, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 2, 24)) ->Tag : Symbol(Tag, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 0, 0)) - -declare function doThat(value: string) : void; ->doThat : Symbol(doThat, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 2, 51)) ->value : Symbol(value, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 3, 24)) - -let value: string; ->value : Symbol(value, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 4, 3)) - -if (isNonBlank(value)) { ->isNonBlank : Symbol(isNonBlank, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 0, 24)) ->value : Symbol(value, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 4, 3)) - - doThis(value); ->doThis : Symbol(doThis, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 1, 69)) ->value : Symbol(value, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 4, 3)) - -} else { - doThat(value); ->doThat : Symbol(doThat, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 2, 51)) ->value : Symbol(value, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 4, 3)) -} - - -const enum Tag2 {} ->Tag2 : Symbol(Tag2, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 9, 1)) - -declare function isNonBlank2(value: string) : value is (string & Tag2); ->isNonBlank2 : Symbol(isNonBlank2, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 12, 18)) ->value : Symbol(value, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 13, 29)) ->value : Symbol(value, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 13, 29)) ->Tag2 : Symbol(Tag2, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 9, 1)) - -declare function doThis2(value: string & Tag2): void; ->doThis2 : Symbol(doThis2, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 13, 71)) ->value : Symbol(value, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 14, 25)) ->Tag2 : Symbol(Tag2, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 9, 1)) - -declare function doThat2(value: string) : void; ->doThat2 : Symbol(doThat2, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 14, 53)) ->value : Symbol(value, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 15, 25)) - -if (isNonBlank2(value)) { ->isNonBlank2 : Symbol(isNonBlank2, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 12, 18)) ->value : Symbol(value, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 4, 3)) - - doThis2(value); ->doThis2 : Symbol(doThis2, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 13, 71)) ->value : Symbol(value, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 4, 3)) - -} else { - doThat2(value); ->doThat2 : Symbol(doThat2, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 14, 53)) ->value : Symbol(value, Decl(typeGuardNarrowsPrimitiveIntersection.ts, 4, 3)) -} - diff --git a/tests/baselines/reference/typeGuardNarrowsPrimitiveIntersection.types b/tests/baselines/reference/typeGuardNarrowsPrimitiveIntersection.types deleted file mode 100644 index 478363669b461..0000000000000 --- a/tests/baselines/reference/typeGuardNarrowsPrimitiveIntersection.types +++ /dev/null @@ -1,76 +0,0 @@ -=== tests/cases/conformance/expressions/typeGuards/typeGuardNarrowsPrimitiveIntersection.ts === -type Tag = {__tag: any}; ->Tag : { __tag: any; } ->__tag : any - -declare function isNonBlank(value: string) : value is (string & Tag); ->isNonBlank : (value: string) => value is string & { __tag: any; } ->value : string ->value : any ->Tag : { __tag: any; } - -declare function doThis(value: string & Tag): void; ->doThis : (value: string & { __tag: any; }) => void ->value : string & { __tag: any; } ->Tag : { __tag: any; } - -declare function doThat(value: string) : void; ->doThat : (value: string) => void ->value : string - -let value: string; ->value : string - -if (isNonBlank(value)) { ->isNonBlank(value) : boolean ->isNonBlank : (value: string) => value is string & { __tag: any; } ->value : string - - doThis(value); ->doThis(value) : void ->doThis : (value: string & { __tag: any; }) => void ->value : string & { __tag: any; } - -} else { - doThat(value); ->doThat(value) : void ->doThat : (value: string) => void ->value : string -} - - -const enum Tag2 {} ->Tag2 : Tag2 - -declare function isNonBlank2(value: string) : value is (string & Tag2); ->isNonBlank2 : (value: string) => value is string & Tag2 ->value : string ->value : any ->Tag2 : Tag2 - -declare function doThis2(value: string & Tag2): void; ->doThis2 : (value: string & Tag2) => void ->value : string & Tag2 ->Tag2 : Tag2 - -declare function doThat2(value: string) : void; ->doThat2 : (value: string) => void ->value : string - -if (isNonBlank2(value)) { ->isNonBlank2(value) : boolean ->isNonBlank2 : (value: string) => value is string & Tag2 ->value : string - - doThis2(value); ->doThis2(value) : void ->doThis2 : (value: string & Tag2) => void ->value : string & Tag2 - -} else { - doThat2(value); ->doThat2(value) : void ->doThat2 : (value: string) => void ->value : string -} - diff --git a/tests/baselines/reference/typeGuardNarrowsToLiteralType.js b/tests/baselines/reference/typeGuardNarrowsToLiteralType.js deleted file mode 100644 index fdd2ee3fb7f75..0000000000000 --- a/tests/baselines/reference/typeGuardNarrowsToLiteralType.js +++ /dev/null @@ -1,21 +0,0 @@ -//// [typeGuardNarrowsToLiteralType.ts] -declare function isFoo(value: string) : value is "foo"; -declare function doThis(value: "foo"): void; -declare function doThat(value: string) : void; -let value: string; -if (isFoo(value)) { - doThis(value); -} else { - doThat(value); -} - - - -//// [typeGuardNarrowsToLiteralType.js] -var value; -if (isFoo(value)) { - doThis(value); -} -else { - doThat(value); -} diff --git a/tests/baselines/reference/typeGuardNarrowsToLiteralType.symbols b/tests/baselines/reference/typeGuardNarrowsToLiteralType.symbols deleted file mode 100644 index 0d0ddc5f00dc1..0000000000000 --- a/tests/baselines/reference/typeGuardNarrowsToLiteralType.symbols +++ /dev/null @@ -1,32 +0,0 @@ -=== tests/cases/conformance/expressions/typeGuards/typeGuardNarrowsToLiteralType.ts === -declare function isFoo(value: string) : value is "foo"; ->isFoo : Symbol(isFoo, Decl(typeGuardNarrowsToLiteralType.ts, 0, 0)) ->value : Symbol(value, Decl(typeGuardNarrowsToLiteralType.ts, 0, 23)) ->value : Symbol(value, Decl(typeGuardNarrowsToLiteralType.ts, 0, 23)) - -declare function doThis(value: "foo"): void; ->doThis : Symbol(doThis, Decl(typeGuardNarrowsToLiteralType.ts, 0, 55)) ->value : Symbol(value, Decl(typeGuardNarrowsToLiteralType.ts, 1, 24)) - -declare function doThat(value: string) : void; ->doThat : Symbol(doThat, Decl(typeGuardNarrowsToLiteralType.ts, 1, 44)) ->value : Symbol(value, Decl(typeGuardNarrowsToLiteralType.ts, 2, 24)) - -let value: string; ->value : Symbol(value, Decl(typeGuardNarrowsToLiteralType.ts, 3, 3)) - -if (isFoo(value)) { ->isFoo : Symbol(isFoo, Decl(typeGuardNarrowsToLiteralType.ts, 0, 0)) ->value : Symbol(value, Decl(typeGuardNarrowsToLiteralType.ts, 3, 3)) - - doThis(value); ->doThis : Symbol(doThis, Decl(typeGuardNarrowsToLiteralType.ts, 0, 55)) ->value : Symbol(value, Decl(typeGuardNarrowsToLiteralType.ts, 3, 3)) - -} else { - doThat(value); ->doThat : Symbol(doThat, Decl(typeGuardNarrowsToLiteralType.ts, 1, 44)) ->value : Symbol(value, Decl(typeGuardNarrowsToLiteralType.ts, 3, 3)) -} - - diff --git a/tests/baselines/reference/typeGuardNarrowsToLiteralType.types b/tests/baselines/reference/typeGuardNarrowsToLiteralType.types deleted file mode 100644 index 9835206deb9f4..0000000000000 --- a/tests/baselines/reference/typeGuardNarrowsToLiteralType.types +++ /dev/null @@ -1,35 +0,0 @@ -=== tests/cases/conformance/expressions/typeGuards/typeGuardNarrowsToLiteralType.ts === -declare function isFoo(value: string) : value is "foo"; ->isFoo : (value: string) => value is "foo" ->value : string ->value : any - -declare function doThis(value: "foo"): void; ->doThis : (value: "foo") => void ->value : "foo" - -declare function doThat(value: string) : void; ->doThat : (value: string) => void ->value : string - -let value: string; ->value : string - -if (isFoo(value)) { ->isFoo(value) : boolean ->isFoo : (value: string) => value is "foo" ->value : string - - doThis(value); ->doThis(value) : void ->doThis : (value: "foo") => void ->value : "foo" - -} else { - doThat(value); ->doThat(value) : void ->doThat : (value: string) => void ->value : string -} - - diff --git a/tests/baselines/reference/typeGuardNarrowsToLiteralTypeUnion.js b/tests/baselines/reference/typeGuardNarrowsToLiteralTypeUnion.js deleted file mode 100644 index 715b362c8e0c2..0000000000000 --- a/tests/baselines/reference/typeGuardNarrowsToLiteralTypeUnion.js +++ /dev/null @@ -1,21 +0,0 @@ -//// [typeGuardNarrowsToLiteralTypeUnion.ts] -declare function isFoo(value: string) : value is ("foo" | "bar"); -declare function doThis(value: "foo" | "bar"): void; -declare function doThat(value: string) : void; -let value: string; -if (isFoo(value)) { - doThis(value); -} else { - doThat(value); -} - - - -//// [typeGuardNarrowsToLiteralTypeUnion.js] -var value; -if (isFoo(value)) { - doThis(value); -} -else { - doThat(value); -} diff --git a/tests/baselines/reference/typeGuardNarrowsToLiteralTypeUnion.symbols b/tests/baselines/reference/typeGuardNarrowsToLiteralTypeUnion.symbols deleted file mode 100644 index 356fa06a06c4a..0000000000000 --- a/tests/baselines/reference/typeGuardNarrowsToLiteralTypeUnion.symbols +++ /dev/null @@ -1,32 +0,0 @@ -=== tests/cases/conformance/expressions/typeGuards/typeGuardNarrowsToLiteralTypeUnion.ts === -declare function isFoo(value: string) : value is ("foo" | "bar"); ->isFoo : Symbol(isFoo, Decl(typeGuardNarrowsToLiteralTypeUnion.ts, 0, 0)) ->value : Symbol(value, Decl(typeGuardNarrowsToLiteralTypeUnion.ts, 0, 23)) ->value : Symbol(value, Decl(typeGuardNarrowsToLiteralTypeUnion.ts, 0, 23)) - -declare function doThis(value: "foo" | "bar"): void; ->doThis : Symbol(doThis, Decl(typeGuardNarrowsToLiteralTypeUnion.ts, 0, 65)) ->value : Symbol(value, Decl(typeGuardNarrowsToLiteralTypeUnion.ts, 1, 24)) - -declare function doThat(value: string) : void; ->doThat : Symbol(doThat, Decl(typeGuardNarrowsToLiteralTypeUnion.ts, 1, 52)) ->value : Symbol(value, Decl(typeGuardNarrowsToLiteralTypeUnion.ts, 2, 24)) - -let value: string; ->value : Symbol(value, Decl(typeGuardNarrowsToLiteralTypeUnion.ts, 3, 3)) - -if (isFoo(value)) { ->isFoo : Symbol(isFoo, Decl(typeGuardNarrowsToLiteralTypeUnion.ts, 0, 0)) ->value : Symbol(value, Decl(typeGuardNarrowsToLiteralTypeUnion.ts, 3, 3)) - - doThis(value); ->doThis : Symbol(doThis, Decl(typeGuardNarrowsToLiteralTypeUnion.ts, 0, 65)) ->value : Symbol(value, Decl(typeGuardNarrowsToLiteralTypeUnion.ts, 3, 3)) - -} else { - doThat(value); ->doThat : Symbol(doThat, Decl(typeGuardNarrowsToLiteralTypeUnion.ts, 1, 52)) ->value : Symbol(value, Decl(typeGuardNarrowsToLiteralTypeUnion.ts, 3, 3)) -} - - diff --git a/tests/baselines/reference/typeGuardNarrowsToLiteralTypeUnion.types b/tests/baselines/reference/typeGuardNarrowsToLiteralTypeUnion.types deleted file mode 100644 index 321a8861d55f5..0000000000000 --- a/tests/baselines/reference/typeGuardNarrowsToLiteralTypeUnion.types +++ /dev/null @@ -1,35 +0,0 @@ -=== tests/cases/conformance/expressions/typeGuards/typeGuardNarrowsToLiteralTypeUnion.ts === -declare function isFoo(value: string) : value is ("foo" | "bar"); ->isFoo : (value: string) => value is "foo" | "bar" ->value : string ->value : any - -declare function doThis(value: "foo" | "bar"): void; ->doThis : (value: "foo" | "bar") => void ->value : "foo" | "bar" - -declare function doThat(value: string) : void; ->doThat : (value: string) => void ->value : string - -let value: string; ->value : string - -if (isFoo(value)) { ->isFoo(value) : boolean ->isFoo : (value: string) => value is "foo" | "bar" ->value : string - - doThis(value); ->doThis(value) : void ->doThis : (value: "foo" | "bar") => void ->value : "foo" | "bar" - -} else { - doThat(value); ->doThat(value) : void ->doThat : (value: string) => void ->value : string -} - - diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardNarrowsPrimitiveIntersection.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardNarrowsPrimitiveIntersection.ts deleted file mode 100644 index 376a78275c83b..0000000000000 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardNarrowsPrimitiveIntersection.ts +++ /dev/null @@ -1,21 +0,0 @@ -type Tag = {__tag: any}; -declare function isNonBlank(value: string) : value is (string & Tag); -declare function doThis(value: string & Tag): void; -declare function doThat(value: string) : void; -let value: string; -if (isNonBlank(value)) { - doThis(value); -} else { - doThat(value); -} - - -const enum Tag2 {} -declare function isNonBlank2(value: string) : value is (string & Tag2); -declare function doThis2(value: string & Tag2): void; -declare function doThat2(value: string) : void; -if (isNonBlank2(value)) { - doThis2(value); -} else { - doThat2(value); -} diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardNarrowsToLiteralType.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardNarrowsToLiteralType.ts deleted file mode 100644 index 3b7d5bba21ab7..0000000000000 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardNarrowsToLiteralType.ts +++ /dev/null @@ -1,10 +0,0 @@ -declare function isFoo(value: string) : value is "foo"; -declare function doThis(value: "foo"): void; -declare function doThat(value: string) : void; -let value: string; -if (isFoo(value)) { - doThis(value); -} else { - doThat(value); -} - diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardNarrowsToLiteralTypeUnion.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardNarrowsToLiteralTypeUnion.ts deleted file mode 100644 index 8f4726160f4b2..0000000000000 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardNarrowsToLiteralTypeUnion.ts +++ /dev/null @@ -1,10 +0,0 @@ -declare function isFoo(value: string) : value is ("foo" | "bar"); -declare function doThis(value: "foo" | "bar"): void; -declare function doThat(value: string) : void; -let value: string; -if (isFoo(value)) { - doThis(value); -} else { - doThat(value); -} -