From 5d3fe0a1d1bbf3c40250004ab3538a0ae16848b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 17 Apr 2025 00:08:08 +0200 Subject: [PATCH 1/9] Improve `.origin` preservation in `getNarrowedTypeWorker` --- src/compiler/checker.ts | 45 ++++++++------- .../reference/controlFlowOptionalChain.types | 8 +-- .../narrowingUnionByUnionCandidate1.js | 42 ++++++++++++++ .../narrowingUnionByUnionCandidate1.symbols | 48 ++++++++++++++++ .../narrowingUnionByUnionCandidate1.types | 57 +++++++++++++++++++ .../reference/narrowingUnionToUnion.types | 4 +- .../narrowingUnionByUnionCandidate1.ts | 19 +++++++ 7 files changed, 196 insertions(+), 27 deletions(-) create mode 100644 tests/baselines/reference/narrowingUnionByUnionCandidate1.js create mode 100644 tests/baselines/reference/narrowingUnionByUnionCandidate1.symbols create mode 100644 tests/baselines/reference/narrowingUnionByUnionCandidate1.types create mode 100644 tests/cases/compiler/narrowingUnionByUnionCandidate1.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 67a733cbbb811..25e17c5b0cc21 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29342,27 +29342,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We first attempt to filter the current type, narrowing constituents as appropriate and removing // constituents that are unrelated to the candidate. const isRelated = checkDerived ? isTypeDerivedFrom : isTypeSubtypeOf; - const keyPropertyName = type.flags & TypeFlags.Union ? getKeyPropertyName(type as UnionType) : undefined; - const narrowedType = mapType(candidate, c => { - // If a discriminant property is available, use that to reduce the type. - const discriminant = keyPropertyName && getTypeOfPropertyOfType(c, keyPropertyName); - const matching = discriminant && getConstituentTypeForKeyType(type as UnionType, discriminant); - // For each constituent t in the current type, if t and and c are directly related, pick the most - // specific of the two. When t and c are related in both directions, we prefer c for type predicates - // because that is the asserted type, but t for `instanceof` because generics aren't reflected in - // prototype object types. - const directlyRelated = mapType( - matching || type, - checkDerived ? - t => isTypeDerivedFrom(t, c) ? t : isTypeDerivedFrom(c, t) ? c : neverType : - t => isTypeStrictSubtypeOf(t, c) ? t : isTypeStrictSubtypeOf(c, t) ? c : isTypeSubtypeOf(t, c) ? t : isTypeSubtypeOf(c, t) ? c : neverType, - ); - // If no constituents are directly related, create intersections for any generic constituents that - // are related by constraint. - return directlyRelated.flags & TypeFlags.Never ? - mapType(type, t => maybeTypeOfKind(t, TypeFlags.Instantiable) && isRelated(c, getBaseConstraintOfType(t) || unknownType) ? getIntersectionType([t, c]) : neverType) : - directlyRelated; - }); + let matchedCandidates: Type[] = []; + let narrowedType = mapType(type, t => + mapType( + candidate, + c => { + const directlyRelated = checkDerived ? + (isTypeDerivedFrom(t, c) ? t : isTypeDerivedFrom(c, t) ? c : neverType) : + (isTypeStrictSubtypeOf(t, c) ? t : isTypeStrictSubtypeOf(c, t) ? c : isTypeSubtypeOf(t, c) ? t : isTypeSubtypeOf(c, t) ? c : neverType); + if (!(directlyRelated.flags & TypeFlags.Never)) { + matchedCandidates = appendIfUnique(matchedCandidates, c); + } + return directlyRelated; + }, + )); + if (matchedCandidates.length !== countTypes(candidate)) { + narrowedType = getUnionType([ + narrowedType, + mapType(candidate, c => { + return !containsType(matchedCandidates, c) + ? mapType(type, t => maybeTypeOfKind(t, TypeFlags.Instantiable) && isRelated(c, getBaseConstraintOfType(t) || unknownType) ? getIntersectionType([t, c]) : neverType) + : neverType; + }), + ]); + } // If filtering produced a non-empty type, return that. Otherwise, pick the most specific of the two // based on assignability, or as a last resort produce an intersection. return !(narrowedType.flags & TypeFlags.Never) ? narrowedType : diff --git a/tests/baselines/reference/controlFlowOptionalChain.types b/tests/baselines/reference/controlFlowOptionalChain.types index 1be51c8e96277..49dbb824dd287 100644 --- a/tests/baselines/reference/controlFlowOptionalChain.types +++ b/tests/baselines/reference/controlFlowOptionalChain.types @@ -2857,12 +2857,12 @@ function f30(o: Thing | undefined) { > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ o.foo; ->o.foo : NonNullable -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>o.foo : string | number +> : ^^^^^^^^^^^^^^^ >o : Thing > : ^^^^^ ->foo : NonNullable -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>foo : string | number +> : ^^^^^^^^^^^^^^^ } } diff --git a/tests/baselines/reference/narrowingUnionByUnionCandidate1.js b/tests/baselines/reference/narrowingUnionByUnionCandidate1.js new file mode 100644 index 0000000000000..d7ab19239e010 --- /dev/null +++ b/tests/baselines/reference/narrowingUnionByUnionCandidate1.js @@ -0,0 +1,42 @@ +//// [tests/cases/compiler/narrowingUnionByUnionCandidate1.ts] //// + +//// [narrowingUnionByUnionCandidate1.ts] +// https://github.com/microsoft/TypeScript/issues/61581 + +type Result = + | { + readonly _tag: "Ok"; + readonly value: A; + } + | { + readonly _tag: "Fail"; + readonly error: E; + }; + +declare const isResult: (u: unknown) => u is Result; + +export const fn = (inp: Result | string) => + isResult(inp) ? inp : "ok"; + + +//// [narrowingUnionByUnionCandidate1.js] +"use strict"; +// https://github.com/microsoft/TypeScript/issues/61581 +Object.defineProperty(exports, "__esModule", { value: true }); +exports.fn = void 0; +var fn = function (inp) { + return isResult(inp) ? inp : "ok"; +}; +exports.fn = fn; + + +//// [narrowingUnionByUnionCandidate1.d.ts] +type Result = { + readonly _tag: "Ok"; + readonly value: A; +} | { + readonly _tag: "Fail"; + readonly error: E; +}; +export declare const fn: (inp: Result | string) => Result | "ok"; +export {}; diff --git a/tests/baselines/reference/narrowingUnionByUnionCandidate1.symbols b/tests/baselines/reference/narrowingUnionByUnionCandidate1.symbols new file mode 100644 index 0000000000000..0f66896222109 --- /dev/null +++ b/tests/baselines/reference/narrowingUnionByUnionCandidate1.symbols @@ -0,0 +1,48 @@ +//// [tests/cases/compiler/narrowingUnionByUnionCandidate1.ts] //// + +=== narrowingUnionByUnionCandidate1.ts === +// https://github.com/microsoft/TypeScript/issues/61581 + +type Result = +>Result : Symbol(Result, Decl(narrowingUnionByUnionCandidate1.ts, 0, 0)) +>A : Symbol(A, Decl(narrowingUnionByUnionCandidate1.ts, 2, 12)) +>E : Symbol(E, Decl(narrowingUnionByUnionCandidate1.ts, 2, 14)) + + | { + readonly _tag: "Ok"; +>_tag : Symbol(_tag, Decl(narrowingUnionByUnionCandidate1.ts, 3, 5)) + + readonly value: A; +>value : Symbol(value, Decl(narrowingUnionByUnionCandidate1.ts, 4, 26)) +>A : Symbol(A, Decl(narrowingUnionByUnionCandidate1.ts, 2, 12)) + } + | { + readonly _tag: "Fail"; +>_tag : Symbol(_tag, Decl(narrowingUnionByUnionCandidate1.ts, 7, 5)) + + readonly error: E; +>error : Symbol(error, Decl(narrowingUnionByUnionCandidate1.ts, 8, 28)) +>E : Symbol(E, Decl(narrowingUnionByUnionCandidate1.ts, 2, 14)) + + }; + +declare const isResult: (u: unknown) => u is Result; +>isResult : Symbol(isResult, Decl(narrowingUnionByUnionCandidate1.ts, 12, 13)) +>u : Symbol(u, Decl(narrowingUnionByUnionCandidate1.ts, 12, 25)) +>u : Symbol(u, Decl(narrowingUnionByUnionCandidate1.ts, 12, 25)) +>Result : Symbol(Result, Decl(narrowingUnionByUnionCandidate1.ts, 0, 0)) + +export const fn = (inp: Result | string) => +>fn : Symbol(fn, Decl(narrowingUnionByUnionCandidate1.ts, 14, 12)) +>A : Symbol(A, Decl(narrowingUnionByUnionCandidate1.ts, 14, 19)) +>E : Symbol(E, Decl(narrowingUnionByUnionCandidate1.ts, 14, 21)) +>inp : Symbol(inp, Decl(narrowingUnionByUnionCandidate1.ts, 14, 25)) +>Result : Symbol(Result, Decl(narrowingUnionByUnionCandidate1.ts, 0, 0)) +>A : Symbol(A, Decl(narrowingUnionByUnionCandidate1.ts, 14, 19)) +>E : Symbol(E, Decl(narrowingUnionByUnionCandidate1.ts, 14, 21)) + + isResult(inp) ? inp : "ok"; +>isResult : Symbol(isResult, Decl(narrowingUnionByUnionCandidate1.ts, 12, 13)) +>inp : Symbol(inp, Decl(narrowingUnionByUnionCandidate1.ts, 14, 25)) +>inp : Symbol(inp, Decl(narrowingUnionByUnionCandidate1.ts, 14, 25)) + diff --git a/tests/baselines/reference/narrowingUnionByUnionCandidate1.types b/tests/baselines/reference/narrowingUnionByUnionCandidate1.types new file mode 100644 index 0000000000000..56c8ee2583cc7 --- /dev/null +++ b/tests/baselines/reference/narrowingUnionByUnionCandidate1.types @@ -0,0 +1,57 @@ +//// [tests/cases/compiler/narrowingUnionByUnionCandidate1.ts] //// + +=== narrowingUnionByUnionCandidate1.ts === +// https://github.com/microsoft/TypeScript/issues/61581 + +type Result = +>Result : Result +> : ^^^^^^^^^^^^ + + | { + readonly _tag: "Ok"; +>_tag : "Ok" +> : ^^^^ + + readonly value: A; +>value : A +> : ^ + } + | { + readonly _tag: "Fail"; +>_tag : "Fail" +> : ^^^^^^ + + readonly error: E; +>error : E +> : ^ + + }; + +declare const isResult: (u: unknown) => u is Result; +>isResult : (u: unknown) => u is Result +> : ^ ^^ ^^^^^ +>u : unknown +> : ^^^^^^^ + +export const fn = (inp: Result | string) => +>fn : (inp: Result | string) => Result | "ok" +> : ^ ^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>(inp: Result | string) => isResult(inp) ? inp : "ok" : (inp: Result | string) => Result | "ok" +> : ^ ^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>inp : string | Result +> : ^^^^^^^^^^^^^^^^^^^^^ + + isResult(inp) ? inp : "ok"; +>isResult(inp) ? inp : "ok" : Result | "ok" +> : ^^^^^^^^^^^^^^^^^^^ +>isResult(inp) : boolean +> : ^^^^^^^ +>isResult : (u: unknown) => u is Result +> : ^ ^^ ^^^^^ +>inp : string | Result +> : ^^^^^^^^^^^^^^^^^^^^^ +>inp : Result +> : ^^^^^^^^^^^^ +>"ok" : "ok" +> : ^^^^ + diff --git a/tests/baselines/reference/narrowingUnionToUnion.types b/tests/baselines/reference/narrowingUnionToUnion.types index f090c9357be17..3bb2435976b33 100644 --- a/tests/baselines/reference/narrowingUnionToUnion.types +++ b/tests/baselines/reference/narrowingUnionToUnion.types @@ -557,8 +557,8 @@ if (isEmpty(test)) { > : ^^^^^^^^^^^^^^^^^^^^^^^^^ test; // EmptyString ->test : EmptyString -> : ^^^^^^^^^^^ +>test : "" | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^^ } // Repro from #43825 diff --git a/tests/cases/compiler/narrowingUnionByUnionCandidate1.ts b/tests/cases/compiler/narrowingUnionByUnionCandidate1.ts new file mode 100644 index 0000000000000..cf59e37ce23a2 --- /dev/null +++ b/tests/cases/compiler/narrowingUnionByUnionCandidate1.ts @@ -0,0 +1,19 @@ +// @strict: true +// @declaration: true + +// https://github.com/microsoft/TypeScript/issues/61581 + +type Result = + | { + readonly _tag: "Ok"; + readonly value: A; + } + | { + readonly _tag: "Fail"; + readonly error: E; + }; + +declare const isResult: (u: unknown) => u is Result; + +export const fn = (inp: Result | string) => + isResult(inp) ? inp : "ok"; From 2eecb4db91dd92faa98f472115398c8423261eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 17 Apr 2025 15:37:11 +0200 Subject: [PATCH 2/9] bring back discriminant logic --- src/compiler/checker.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 25e17c5b0cc21..f1e72d1b130bb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29342,9 +29342,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We first attempt to filter the current type, narrowing constituents as appropriate and removing // constituents that are unrelated to the candidate. const isRelated = checkDerived ? isTypeDerivedFrom : isTypeSubtypeOf; + const keyPropertyName = type.flags & TypeFlags.Union ? getKeyPropertyName(type as UnionType) : undefined; + const discriminantMatchingType = keyPropertyName ? + mapType(candidate, c => { + const discriminant = keyPropertyName && getTypeOfPropertyOfType(c, keyPropertyName); + return (discriminant && getConstituentTypeForKeyType(type as UnionType, discriminant)) ?? neverType; + }) : + neverType; let matchedCandidates: Type[] = []; - let narrowedType = mapType(type, t => - mapType( + let narrowedType = mapType( + !(discriminantMatchingType.flags & TypeFlags.Never) ? discriminantMatchingType : type, + t => mapType( candidate, c => { const directlyRelated = checkDerived ? @@ -29355,7 +29363,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return directlyRelated; }, - )); + ), + ); if (matchedCandidates.length !== countTypes(candidate)) { narrowedType = getUnionType([ narrowedType, From 83bab0d98acc3dc54cccb42dc2c44e4ea01c2ceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 17 Apr 2025 15:38:36 +0200 Subject: [PATCH 3/9] Revert "bring back discriminant logic" This reverts commit 2eecb4db91dd92faa98f472115398c8423261eca. --- src/compiler/checker.ts | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f1e72d1b130bb..25e17c5b0cc21 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29342,17 +29342,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We first attempt to filter the current type, narrowing constituents as appropriate and removing // constituents that are unrelated to the candidate. const isRelated = checkDerived ? isTypeDerivedFrom : isTypeSubtypeOf; - const keyPropertyName = type.flags & TypeFlags.Union ? getKeyPropertyName(type as UnionType) : undefined; - const discriminantMatchingType = keyPropertyName ? - mapType(candidate, c => { - const discriminant = keyPropertyName && getTypeOfPropertyOfType(c, keyPropertyName); - return (discriminant && getConstituentTypeForKeyType(type as UnionType, discriminant)) ?? neverType; - }) : - neverType; let matchedCandidates: Type[] = []; - let narrowedType = mapType( - !(discriminantMatchingType.flags & TypeFlags.Never) ? discriminantMatchingType : type, - t => mapType( + let narrowedType = mapType(type, t => + mapType( candidate, c => { const directlyRelated = checkDerived ? @@ -29363,8 +29355,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return directlyRelated; }, - ), - ); + )); if (matchedCandidates.length !== countTypes(candidate)) { narrowedType = getUnionType([ narrowedType, From 40ebaee88cb8a5850f5b443111589f0e01c94ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 17 Apr 2025 15:40:24 +0200 Subject: [PATCH 4/9] brign back comments --- src/compiler/checker.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 25e17c5b0cc21..b68ca76d247b6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29347,6 +29347,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { mapType( candidate, c => { + // For each constituent t in the current type, if t and and c are directly related, pick the most + // specific of the two. When t and c are related in both directions, we prefer c for type predicates + // because that is the asserted type, but t for `instanceof` because generics aren't reflected in + // prototype object types. const directlyRelated = checkDerived ? (isTypeDerivedFrom(t, c) ? t : isTypeDerivedFrom(c, t) ? c : neverType) : (isTypeStrictSubtypeOf(t, c) ? t : isTypeStrictSubtypeOf(c, t) ? c : isTypeSubtypeOf(t, c) ? t : isTypeSubtypeOf(c, t) ? c : neverType); @@ -29357,6 +29361,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }, )); if (matchedCandidates.length !== countTypes(candidate)) { + // If there are leftover constituents not directly related, create intersections for any generic constituents that + // are related by constraint. narrowedType = getUnionType([ narrowedType, mapType(candidate, c => { From 2097c676e0481a99c7af0465229eee9a546c64ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 17 Apr 2025 15:48:47 +0200 Subject: [PATCH 5/9] Bring the discriminant logic back in a different form --- src/compiler/checker.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b68ca76d247b6..37350ed4105de 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29342,11 +29342,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We first attempt to filter the current type, narrowing constituents as appropriate and removing // constituents that are unrelated to the candidate. const isRelated = checkDerived ? isTypeDerivedFrom : isTypeSubtypeOf; + const keyPropertyName = type.flags & TypeFlags.Union ? getKeyPropertyName(type as UnionType) : undefined; let matchedCandidates: Type[] = []; let narrowedType = mapType(type, t => mapType( candidate, c => { + if (keyPropertyName) { + // If a discriminant property is available, use only matching constituents to reduce the type. + const discriminant = keyPropertyName && getTypeOfPropertyOfType(c, keyPropertyName); + if (!discriminant || getConstituentTypeForKeyType(type as UnionType, discriminant) !== t) { + return neverType; + } + } // For each constituent t in the current type, if t and and c are directly related, pick the most // specific of the two. When t and c are related in both directions, we prefer c for type predicates // because that is the asserted type, but t for `instanceof` because generics aren't reflected in From 5c8de5d6e5cd0613ffe210847392b2aa2f9cc6ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 17 Apr 2025 15:56:14 +0200 Subject: [PATCH 6/9] add comment --- .../narrowingUnionByUnionCandidate1.js | 2 ++ .../narrowingUnionByUnionCandidate1.symbols | 17 +++++++++-------- .../narrowingUnionByUnionCandidate1.types | 1 + .../compiler/narrowingUnionByUnionCandidate1.ts | 1 + 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/tests/baselines/reference/narrowingUnionByUnionCandidate1.js b/tests/baselines/reference/narrowingUnionByUnionCandidate1.js index d7ab19239e010..d13ff5d255d40 100644 --- a/tests/baselines/reference/narrowingUnionByUnionCandidate1.js +++ b/tests/baselines/reference/narrowingUnionByUnionCandidate1.js @@ -15,6 +15,7 @@ type Result = declare const isResult: (u: unknown) => u is Result; +// return type: Result | "ok" export const fn = (inp: Result | string) => isResult(inp) ? inp : "ok"; @@ -24,6 +25,7 @@ export const fn = (inp: Result | string) => // https://github.com/microsoft/TypeScript/issues/61581 Object.defineProperty(exports, "__esModule", { value: true }); exports.fn = void 0; +// return type: Result | "ok" var fn = function (inp) { return isResult(inp) ? inp : "ok"; }; diff --git a/tests/baselines/reference/narrowingUnionByUnionCandidate1.symbols b/tests/baselines/reference/narrowingUnionByUnionCandidate1.symbols index 0f66896222109..0349e9222c601 100644 --- a/tests/baselines/reference/narrowingUnionByUnionCandidate1.symbols +++ b/tests/baselines/reference/narrowingUnionByUnionCandidate1.symbols @@ -32,17 +32,18 @@ declare const isResult: (u: unknown) => u is Result; >u : Symbol(u, Decl(narrowingUnionByUnionCandidate1.ts, 12, 25)) >Result : Symbol(Result, Decl(narrowingUnionByUnionCandidate1.ts, 0, 0)) +// return type: Result | "ok" export const fn = (inp: Result | string) => ->fn : Symbol(fn, Decl(narrowingUnionByUnionCandidate1.ts, 14, 12)) ->A : Symbol(A, Decl(narrowingUnionByUnionCandidate1.ts, 14, 19)) ->E : Symbol(E, Decl(narrowingUnionByUnionCandidate1.ts, 14, 21)) ->inp : Symbol(inp, Decl(narrowingUnionByUnionCandidate1.ts, 14, 25)) +>fn : Symbol(fn, Decl(narrowingUnionByUnionCandidate1.ts, 15, 12)) +>A : Symbol(A, Decl(narrowingUnionByUnionCandidate1.ts, 15, 19)) +>E : Symbol(E, Decl(narrowingUnionByUnionCandidate1.ts, 15, 21)) +>inp : Symbol(inp, Decl(narrowingUnionByUnionCandidate1.ts, 15, 25)) >Result : Symbol(Result, Decl(narrowingUnionByUnionCandidate1.ts, 0, 0)) ->A : Symbol(A, Decl(narrowingUnionByUnionCandidate1.ts, 14, 19)) ->E : Symbol(E, Decl(narrowingUnionByUnionCandidate1.ts, 14, 21)) +>A : Symbol(A, Decl(narrowingUnionByUnionCandidate1.ts, 15, 19)) +>E : Symbol(E, Decl(narrowingUnionByUnionCandidate1.ts, 15, 21)) isResult(inp) ? inp : "ok"; >isResult : Symbol(isResult, Decl(narrowingUnionByUnionCandidate1.ts, 12, 13)) ->inp : Symbol(inp, Decl(narrowingUnionByUnionCandidate1.ts, 14, 25)) ->inp : Symbol(inp, Decl(narrowingUnionByUnionCandidate1.ts, 14, 25)) +>inp : Symbol(inp, Decl(narrowingUnionByUnionCandidate1.ts, 15, 25)) +>inp : Symbol(inp, Decl(narrowingUnionByUnionCandidate1.ts, 15, 25)) diff --git a/tests/baselines/reference/narrowingUnionByUnionCandidate1.types b/tests/baselines/reference/narrowingUnionByUnionCandidate1.types index 56c8ee2583cc7..5e4022547d5d7 100644 --- a/tests/baselines/reference/narrowingUnionByUnionCandidate1.types +++ b/tests/baselines/reference/narrowingUnionByUnionCandidate1.types @@ -33,6 +33,7 @@ declare const isResult: (u: unknown) => u is Result; >u : unknown > : ^^^^^^^ +// return type: Result | "ok" export const fn = (inp: Result | string) => >fn : (inp: Result | string) => Result | "ok" > : ^ ^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/cases/compiler/narrowingUnionByUnionCandidate1.ts b/tests/cases/compiler/narrowingUnionByUnionCandidate1.ts index cf59e37ce23a2..27ccf28d60277 100644 --- a/tests/cases/compiler/narrowingUnionByUnionCandidate1.ts +++ b/tests/cases/compiler/narrowingUnionByUnionCandidate1.ts @@ -15,5 +15,6 @@ type Result = declare const isResult: (u: unknown) => u is Result; +// return type: Result | "ok" export const fn = (inp: Result | string) => isResult(inp) ? inp : "ok"; From f3f4f5b032d5aaf8676c072fa4890b086fca3c8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 18 Apr 2025 21:33:37 +0200 Subject: [PATCH 7/9] fixed narrowing by a type without a discriminant --- src/compiler/checker.ts | 2 +- .../reference/narrowingUnionToUnion2.symbols | 314 +++++++++++++++ .../reference/narrowingUnionToUnion2.types | 365 ++++++++++++++++++ .../reference/narrowingUnionToUnion3.symbols | 273 +++++++++++++ .../reference/narrowingUnionToUnion3.types | 327 ++++++++++++++++ .../cases/compiler/narrowingUnionToUnion2.ts | 120 ++++++ .../cases/compiler/narrowingUnionToUnion3.ts | 102 +++++ 7 files changed, 1502 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/narrowingUnionToUnion2.symbols create mode 100644 tests/baselines/reference/narrowingUnionToUnion2.types create mode 100644 tests/baselines/reference/narrowingUnionToUnion3.symbols create mode 100644 tests/baselines/reference/narrowingUnionToUnion3.types create mode 100644 tests/cases/compiler/narrowingUnionToUnion2.ts create mode 100644 tests/cases/compiler/narrowingUnionToUnion3.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 37350ed4105de..b41fcb213ae09 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29351,7 +29351,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (keyPropertyName) { // If a discriminant property is available, use only matching constituents to reduce the type. const discriminant = keyPropertyName && getTypeOfPropertyOfType(c, keyPropertyName); - if (!discriminant || getConstituentTypeForKeyType(type as UnionType, discriminant) !== t) { + if (discriminant && getConstituentTypeForKeyType(type as UnionType, discriminant) !== t) { return neverType; } } diff --git a/tests/baselines/reference/narrowingUnionToUnion2.symbols b/tests/baselines/reference/narrowingUnionToUnion2.symbols new file mode 100644 index 0000000000000..eb8ef524b681e --- /dev/null +++ b/tests/baselines/reference/narrowingUnionToUnion2.symbols @@ -0,0 +1,314 @@ +//// [tests/cases/compiler/narrowingUnionToUnion2.ts] //// + +=== narrowingUnionToUnion2.ts === +interface NodeMap { +>NodeMap : Symbol(NodeMap, Decl(narrowingUnionToUnion2.ts, 0, 0)) + + ClassBody: ClassBody; +>ClassBody : Symbol(NodeMap.ClassBody, Decl(narrowingUnionToUnion2.ts, 0, 19)) +>ClassBody : Symbol(ClassBody, Decl(narrowingUnionToUnion2.ts, 88, 1)) + + Expression: Expression; +>Expression : Symbol(NodeMap.Expression, Decl(narrowingUnionToUnion2.ts, 1, 23)) +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion2.ts, 39, 1)) + + Function: Function; +>Function : Symbol(NodeMap.Function, Decl(narrowingUnionToUnion2.ts, 2, 25)) +>Function : Symbol(Function, Decl(narrowingUnionToUnion2.ts, 8, 35)) + + PropertyDefinition: PropertyDefinition; +>PropertyDefinition : Symbol(NodeMap.PropertyDefinition, Decl(narrowingUnionToUnion2.ts, 3, 21)) +>PropertyDefinition : Symbol(PropertyDefinition, Decl(narrowingUnionToUnion2.ts, 45, 1)) + + Statement: Statement; +>Statement : Symbol(NodeMap.Statement, Decl(narrowingUnionToUnion2.ts, 4, 41)) +>Statement : Symbol(Statement, Decl(narrowingUnionToUnion2.ts, 13, 28)) +} + +type Node = NodeMap[keyof NodeMap]; +>Node : Symbol(Node, Decl(narrowingUnionToUnion2.ts, 6, 1)) +>NodeMap : Symbol(NodeMap, Decl(narrowingUnionToUnion2.ts, 0, 0)) +>NodeMap : Symbol(NodeMap, Decl(narrowingUnionToUnion2.ts, 0, 0)) + +type Function = +>Function : Symbol(Function, Decl(narrowingUnionToUnion2.ts, 8, 35)) + + | FunctionDeclaration +>FunctionDeclaration : Symbol(FunctionDeclaration, Decl(narrowingUnionToUnion2.ts, 24, 1)) + + | FunctionExpression +>FunctionExpression : Symbol(FunctionExpression, Decl(narrowingUnionToUnion2.ts, 50, 1)) + + | ArrowFunctionExpression; +>ArrowFunctionExpression : Symbol(ArrowFunctionExpression, Decl(narrowingUnionToUnion2.ts, 83, 1)) + +type Statement = BlockStatement | ReturnStatement; +>Statement : Symbol(Statement, Decl(narrowingUnionToUnion2.ts, 13, 28)) +>BlockStatement : Symbol(BlockStatement, Decl(narrowingUnionToUnion2.ts, 15, 50)) +>ReturnStatement : Symbol(ReturnStatement, Decl(narrowingUnionToUnion2.ts, 20, 1)) + +interface BlockStatement { +>BlockStatement : Symbol(BlockStatement, Decl(narrowingUnionToUnion2.ts, 15, 50)) + + type: "BlockStatement"; +>type : Symbol(BlockStatement.type, Decl(narrowingUnionToUnion2.ts, 17, 26)) + + body: Statement[]; +>body : Symbol(BlockStatement.body, Decl(narrowingUnionToUnion2.ts, 18, 25)) +>Statement : Symbol(Statement, Decl(narrowingUnionToUnion2.ts, 13, 28)) +} + +interface ReturnStatement { +>ReturnStatement : Symbol(ReturnStatement, Decl(narrowingUnionToUnion2.ts, 20, 1)) + + type: "ReturnStatement"; +>type : Symbol(ReturnStatement.type, Decl(narrowingUnionToUnion2.ts, 22, 27)) +} + +interface FunctionDeclaration { +>FunctionDeclaration : Symbol(FunctionDeclaration, Decl(narrowingUnionToUnion2.ts, 24, 1)) + + type: "FunctionDeclaration"; +>type : Symbol(FunctionDeclaration.type, Decl(narrowingUnionToUnion2.ts, 26, 31)) + + body: BlockStatement; +>body : Symbol(FunctionDeclaration.body, Decl(narrowingUnionToUnion2.ts, 27, 30)) +>BlockStatement : Symbol(BlockStatement, Decl(narrowingUnionToUnion2.ts, 15, 50)) +} + +interface ExpressionMap { +>ExpressionMap : Symbol(ExpressionMap, Decl(narrowingUnionToUnion2.ts, 29, 1)) + + ArrowFunctionExpression: ArrowFunctionExpression; +>ArrowFunctionExpression : Symbol(ExpressionMap.ArrowFunctionExpression, Decl(narrowingUnionToUnion2.ts, 31, 25)) +>ArrowFunctionExpression : Symbol(ArrowFunctionExpression, Decl(narrowingUnionToUnion2.ts, 83, 1)) + + ClassExpression: ClassExpression; +>ClassExpression : Symbol(ExpressionMap.ClassExpression, Decl(narrowingUnionToUnion2.ts, 32, 51)) +>ClassExpression : Symbol(ClassExpression, Decl(narrowingUnionToUnion2.ts, 93, 1)) + + FunctionExpression: FunctionExpression; +>FunctionExpression : Symbol(ExpressionMap.FunctionExpression, Decl(narrowingUnionToUnion2.ts, 33, 35)) +>FunctionExpression : Symbol(FunctionExpression, Decl(narrowingUnionToUnion2.ts, 50, 1)) + + Identifier: Identifier; +>Identifier : Symbol(ExpressionMap.Identifier, Decl(narrowingUnionToUnion2.ts, 34, 41)) +>Identifier : Symbol(Identifier, Decl(narrowingUnionToUnion2.ts, 61, 1)) + + Literal: Literal; +>Literal : Symbol(ExpressionMap.Literal, Decl(narrowingUnionToUnion2.ts, 35, 25)) +>Literal : Symbol(Literal, Decl(narrowingUnionToUnion2.ts, 66, 1)) + + NewExpression: NewExpression; +>NewExpression : Symbol(ExpressionMap.NewExpression, Decl(narrowingUnionToUnion2.ts, 36, 19)) +>NewExpression : Symbol(NewExpression, Decl(narrowingUnionToUnion2.ts, 55, 1)) + + ObjectExpression: ObjectExpression; +>ObjectExpression : Symbol(ExpressionMap.ObjectExpression, Decl(narrowingUnionToUnion2.ts, 37, 31)) +>ObjectExpression : Symbol(ObjectExpression, Decl(narrowingUnionToUnion2.ts, 41, 53)) +} + +type Expression = ExpressionMap[keyof ExpressionMap]; +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion2.ts, 39, 1)) +>ExpressionMap : Symbol(ExpressionMap, Decl(narrowingUnionToUnion2.ts, 29, 1)) +>ExpressionMap : Symbol(ExpressionMap, Decl(narrowingUnionToUnion2.ts, 29, 1)) + +interface ObjectExpression { +>ObjectExpression : Symbol(ObjectExpression, Decl(narrowingUnionToUnion2.ts, 41, 53)) + + type: "ObjectExpression"; +>type : Symbol(ObjectExpression.type, Decl(narrowingUnionToUnion2.ts, 43, 28)) +} + +interface PropertyDefinition { +>PropertyDefinition : Symbol(PropertyDefinition, Decl(narrowingUnionToUnion2.ts, 45, 1)) + + type: "PropertyDefinition"; +>type : Symbol(PropertyDefinition.type, Decl(narrowingUnionToUnion2.ts, 47, 30)) + + key: Expression; +>key : Symbol(PropertyDefinition.key, Decl(narrowingUnionToUnion2.ts, 48, 29)) +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion2.ts, 39, 1)) +} + +interface FunctionExpression { +>FunctionExpression : Symbol(FunctionExpression, Decl(narrowingUnionToUnion2.ts, 50, 1)) + + type: "FunctionExpression"; +>type : Symbol(FunctionExpression.type, Decl(narrowingUnionToUnion2.ts, 52, 30)) + + body: BlockStatement; +>body : Symbol(FunctionExpression.body, Decl(narrowingUnionToUnion2.ts, 53, 29)) +>BlockStatement : Symbol(BlockStatement, Decl(narrowingUnionToUnion2.ts, 15, 50)) +} + +interface NewExpression { +>NewExpression : Symbol(NewExpression, Decl(narrowingUnionToUnion2.ts, 55, 1)) + + type: "NewExpression"; +>type : Symbol(NewExpression.type, Decl(narrowingUnionToUnion2.ts, 57, 25)) + + callee: Expression; +>callee : Symbol(NewExpression.callee, Decl(narrowingUnionToUnion2.ts, 58, 24)) +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion2.ts, 39, 1)) + + arguments: Array; +>arguments : Symbol(NewExpression.arguments, Decl(narrowingUnionToUnion2.ts, 59, 21)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion2.ts, 39, 1)) +} + +interface Identifier { +>Identifier : Symbol(Identifier, Decl(narrowingUnionToUnion2.ts, 61, 1)) + + type: "Identifier"; +>type : Symbol(Identifier.type, Decl(narrowingUnionToUnion2.ts, 63, 22)) + + name: string; +>name : Symbol(Identifier.name, Decl(narrowingUnionToUnion2.ts, 64, 21)) +} + +type Literal = SimpleLiteral | RegExpLiteral | BigIntLiteral; +>Literal : Symbol(Literal, Decl(narrowingUnionToUnion2.ts, 66, 1)) +>SimpleLiteral : Symbol(SimpleLiteral, Decl(narrowingUnionToUnion2.ts, 68, 61)) +>RegExpLiteral : Symbol(RegExpLiteral, Decl(narrowingUnionToUnion2.ts, 73, 1)) +>BigIntLiteral : Symbol(BigIntLiteral, Decl(narrowingUnionToUnion2.ts, 78, 1)) + +interface SimpleLiteral { +>SimpleLiteral : Symbol(SimpleLiteral, Decl(narrowingUnionToUnion2.ts, 68, 61)) + + type: "Literal"; +>type : Symbol(SimpleLiteral.type, Decl(narrowingUnionToUnion2.ts, 70, 25)) + + value: string | boolean | number | null; +>value : Symbol(SimpleLiteral.value, Decl(narrowingUnionToUnion2.ts, 71, 18)) +} + +interface RegExpLiteral { +>RegExpLiteral : Symbol(RegExpLiteral, Decl(narrowingUnionToUnion2.ts, 73, 1)) + + type: "Literal"; +>type : Symbol(RegExpLiteral.type, Decl(narrowingUnionToUnion2.ts, 75, 25)) + + value: RegExp; +>value : Symbol(RegExpLiteral.value, Decl(narrowingUnionToUnion2.ts, 76, 18)) +>RegExp : Symbol(RegExp, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +} + +interface BigIntLiteral { +>BigIntLiteral : Symbol(BigIntLiteral, Decl(narrowingUnionToUnion2.ts, 78, 1)) + + type: "Literal"; +>type : Symbol(BigIntLiteral.type, Decl(narrowingUnionToUnion2.ts, 80, 25)) + + value: bigint; +>value : Symbol(BigIntLiteral.value, Decl(narrowingUnionToUnion2.ts, 81, 18)) +} + +interface ArrowFunctionExpression { +>ArrowFunctionExpression : Symbol(ArrowFunctionExpression, Decl(narrowingUnionToUnion2.ts, 83, 1)) + + type: "ArrowFunctionExpression"; +>type : Symbol(ArrowFunctionExpression.type, Decl(narrowingUnionToUnion2.ts, 85, 35)) + + body: BlockStatement | Expression; +>body : Symbol(ArrowFunctionExpression.body, Decl(narrowingUnionToUnion2.ts, 86, 34)) +>BlockStatement : Symbol(BlockStatement, Decl(narrowingUnionToUnion2.ts, 15, 50)) +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion2.ts, 39, 1)) +} + +interface ClassBody { +>ClassBody : Symbol(ClassBody, Decl(narrowingUnionToUnion2.ts, 88, 1)) + + type: "ClassBody"; +>type : Symbol(ClassBody.type, Decl(narrowingUnionToUnion2.ts, 90, 21)) + + body: Array; +>body : Symbol(ClassBody.body, Decl(narrowingUnionToUnion2.ts, 91, 20)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>PropertyDefinition : Symbol(PropertyDefinition, Decl(narrowingUnionToUnion2.ts, 45, 1)) +} + +interface ClassExpression { +>ClassExpression : Symbol(ClassExpression, Decl(narrowingUnionToUnion2.ts, 93, 1)) + + type: "ClassExpression"; +>type : Symbol(ClassExpression.type, Decl(narrowingUnionToUnion2.ts, 95, 27)) + + body: ClassBody; +>body : Symbol(ClassExpression.body, Decl(narrowingUnionToUnion2.ts, 96, 26)) +>ClassBody : Symbol(ClassBody, Decl(narrowingUnionToUnion2.ts, 88, 1)) +} + +export function getNestedReturnStatements(node: Node): Array { +>getNestedReturnStatements : Symbol(getNestedReturnStatements, Decl(narrowingUnionToUnion2.ts, 98, 1)) +>node : Symbol(node, Decl(narrowingUnionToUnion2.ts, 100, 42)) +>Node : Symbol(Node, Decl(narrowingUnionToUnion2.ts, 6, 1)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>ReturnStatement : Symbol(ReturnStatement, Decl(narrowingUnionToUnion2.ts, 20, 1)) + + const returnStatements: Array = []; +>returnStatements : Symbol(returnStatements, Decl(narrowingUnionToUnion2.ts, 101, 7)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>ReturnStatement : Symbol(ReturnStatement, Decl(narrowingUnionToUnion2.ts, 20, 1)) + + if (node.type === "ReturnStatement") { +>node.type : Symbol(type, Decl(narrowingUnionToUnion2.ts, 90, 21), Decl(narrowingUnionToUnion2.ts, 85, 35), Decl(narrowingUnionToUnion2.ts, 95, 27), Decl(narrowingUnionToUnion2.ts, 52, 30), Decl(narrowingUnionToUnion2.ts, 63, 22) ... and 9 more) +>node : Symbol(node, Decl(narrowingUnionToUnion2.ts, 100, 42)) +>type : Symbol(type, Decl(narrowingUnionToUnion2.ts, 90, 21), Decl(narrowingUnionToUnion2.ts, 85, 35), Decl(narrowingUnionToUnion2.ts, 95, 27), Decl(narrowingUnionToUnion2.ts, 52, 30), Decl(narrowingUnionToUnion2.ts, 63, 22) ... and 9 more) + + returnStatements.push(node); +>returnStatements.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>returnStatements : Symbol(returnStatements, Decl(narrowingUnionToUnion2.ts, 101, 7)) +>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>node : Symbol(node, Decl(narrowingUnionToUnion2.ts, 100, 42)) + } + + if ("body" in node && node.body !== undefined && node.body !== null) { +>node : Symbol(node, Decl(narrowingUnionToUnion2.ts, 100, 42)) +>node.body : Symbol(body, Decl(narrowingUnionToUnion2.ts, 91, 20), Decl(narrowingUnionToUnion2.ts, 86, 34), Decl(narrowingUnionToUnion2.ts, 96, 26), Decl(narrowingUnionToUnion2.ts, 53, 29), Decl(narrowingUnionToUnion2.ts, 27, 30) ... and 1 more) +>node : Symbol(node, Decl(narrowingUnionToUnion2.ts, 100, 42)) +>body : Symbol(body, Decl(narrowingUnionToUnion2.ts, 91, 20), Decl(narrowingUnionToUnion2.ts, 86, 34), Decl(narrowingUnionToUnion2.ts, 96, 26), Decl(narrowingUnionToUnion2.ts, 53, 29), Decl(narrowingUnionToUnion2.ts, 27, 30) ... and 1 more) +>undefined : Symbol(undefined) +>node.body : Symbol(body, Decl(narrowingUnionToUnion2.ts, 91, 20), Decl(narrowingUnionToUnion2.ts, 86, 34), Decl(narrowingUnionToUnion2.ts, 96, 26), Decl(narrowingUnionToUnion2.ts, 53, 29), Decl(narrowingUnionToUnion2.ts, 27, 30) ... and 1 more) +>node : Symbol(node, Decl(narrowingUnionToUnion2.ts, 100, 42)) +>body : Symbol(body, Decl(narrowingUnionToUnion2.ts, 91, 20), Decl(narrowingUnionToUnion2.ts, 86, 34), Decl(narrowingUnionToUnion2.ts, 96, 26), Decl(narrowingUnionToUnion2.ts, 53, 29), Decl(narrowingUnionToUnion2.ts, 27, 30) ... and 1 more) + + Array.isArray(node.body) +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>node.body : Symbol(body, Decl(narrowingUnionToUnion2.ts, 91, 20), Decl(narrowingUnionToUnion2.ts, 86, 34), Decl(narrowingUnionToUnion2.ts, 96, 26), Decl(narrowingUnionToUnion2.ts, 53, 29), Decl(narrowingUnionToUnion2.ts, 27, 30) ... and 1 more) +>node : Symbol(node, Decl(narrowingUnionToUnion2.ts, 100, 42)) +>body : Symbol(body, Decl(narrowingUnionToUnion2.ts, 91, 20), Decl(narrowingUnionToUnion2.ts, 86, 34), Decl(narrowingUnionToUnion2.ts, 96, 26), Decl(narrowingUnionToUnion2.ts, 53, 29), Decl(narrowingUnionToUnion2.ts, 27, 30) ... and 1 more) + + ? node.body.forEach((x) => { +>node.body.forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>node.body : Symbol(body, Decl(narrowingUnionToUnion2.ts, 91, 20), Decl(narrowingUnionToUnion2.ts, 86, 34), Decl(narrowingUnionToUnion2.ts, 96, 26), Decl(narrowingUnionToUnion2.ts, 53, 29), Decl(narrowingUnionToUnion2.ts, 27, 30) ... and 1 more) +>node : Symbol(node, Decl(narrowingUnionToUnion2.ts, 100, 42)) +>body : Symbol(body, Decl(narrowingUnionToUnion2.ts, 91, 20), Decl(narrowingUnionToUnion2.ts, 86, 34), Decl(narrowingUnionToUnion2.ts, 96, 26), Decl(narrowingUnionToUnion2.ts, 53, 29), Decl(narrowingUnionToUnion2.ts, 27, 30) ... and 1 more) +>forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(narrowingUnionToUnion2.ts, 109, 27)) + + returnStatements.push(...getNestedReturnStatements(x)); +>returnStatements.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>returnStatements : Symbol(returnStatements, Decl(narrowingUnionToUnion2.ts, 101, 7)) +>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>getNestedReturnStatements : Symbol(getNestedReturnStatements, Decl(narrowingUnionToUnion2.ts, 98, 1)) +>x : Symbol(x, Decl(narrowingUnionToUnion2.ts, 109, 27)) + + }) + : returnStatements.push(...getNestedReturnStatements(node.body)); +>returnStatements.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>returnStatements : Symbol(returnStatements, Decl(narrowingUnionToUnion2.ts, 101, 7)) +>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>getNestedReturnStatements : Symbol(getNestedReturnStatements, Decl(narrowingUnionToUnion2.ts, 98, 1)) +>node.body : Symbol(body, Decl(narrowingUnionToUnion2.ts, 91, 20), Decl(narrowingUnionToUnion2.ts, 86, 34), Decl(narrowingUnionToUnion2.ts, 96, 26), Decl(narrowingUnionToUnion2.ts, 53, 29), Decl(narrowingUnionToUnion2.ts, 27, 30) ... and 1 more) +>node : Symbol(node, Decl(narrowingUnionToUnion2.ts, 100, 42)) +>body : Symbol(body, Decl(narrowingUnionToUnion2.ts, 91, 20), Decl(narrowingUnionToUnion2.ts, 86, 34), Decl(narrowingUnionToUnion2.ts, 96, 26), Decl(narrowingUnionToUnion2.ts, 53, 29), Decl(narrowingUnionToUnion2.ts, 27, 30) ... and 1 more) + } + + return returnStatements; +>returnStatements : Symbol(returnStatements, Decl(narrowingUnionToUnion2.ts, 101, 7)) +} + diff --git a/tests/baselines/reference/narrowingUnionToUnion2.types b/tests/baselines/reference/narrowingUnionToUnion2.types new file mode 100644 index 0000000000000..5915423963e82 --- /dev/null +++ b/tests/baselines/reference/narrowingUnionToUnion2.types @@ -0,0 +1,365 @@ +//// [tests/cases/compiler/narrowingUnionToUnion2.ts] //// + +=== narrowingUnionToUnion2.ts === +interface NodeMap { + ClassBody: ClassBody; +>ClassBody : ClassBody +> : ^^^^^^^^^ + + Expression: Expression; +>Expression : Expression +> : ^^^^^^^^^^ + + Function: Function; +>Function : Function +> : ^^^^^^^^ + + PropertyDefinition: PropertyDefinition; +>PropertyDefinition : PropertyDefinition +> : ^^^^^^^^^^^^^^^^^^ + + Statement: Statement; +>Statement : Statement +> : ^^^^^^^^^ +} + +type Node = NodeMap[keyof NodeMap]; +>Node : Node +> : ^^^^ + +type Function = +>Function : Function +> : ^^^^^^^^ + + | FunctionDeclaration + | FunctionExpression + | ArrowFunctionExpression; + +type Statement = BlockStatement | ReturnStatement; +>Statement : Statement +> : ^^^^^^^^^ + +interface BlockStatement { + type: "BlockStatement"; +>type : "BlockStatement" +> : ^^^^^^^^^^^^^^^^ + + body: Statement[]; +>body : Statement[] +> : ^^^^^^^^^^^ +} + +interface ReturnStatement { + type: "ReturnStatement"; +>type : "ReturnStatement" +> : ^^^^^^^^^^^^^^^^^ +} + +interface FunctionDeclaration { + type: "FunctionDeclaration"; +>type : "FunctionDeclaration" +> : ^^^^^^^^^^^^^^^^^^^^^ + + body: BlockStatement; +>body : BlockStatement +> : ^^^^^^^^^^^^^^ +} + +interface ExpressionMap { + ArrowFunctionExpression: ArrowFunctionExpression; +>ArrowFunctionExpression : ArrowFunctionExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^ + + ClassExpression: ClassExpression; +>ClassExpression : ClassExpression +> : ^^^^^^^^^^^^^^^ + + FunctionExpression: FunctionExpression; +>FunctionExpression : FunctionExpression +> : ^^^^^^^^^^^^^^^^^^ + + Identifier: Identifier; +>Identifier : Identifier +> : ^^^^^^^^^^ + + Literal: Literal; +>Literal : Literal +> : ^^^^^^^ + + NewExpression: NewExpression; +>NewExpression : NewExpression +> : ^^^^^^^^^^^^^ + + ObjectExpression: ObjectExpression; +>ObjectExpression : ObjectExpression +> : ^^^^^^^^^^^^^^^^ +} + +type Expression = ExpressionMap[keyof ExpressionMap]; +>Expression : Expression +> : ^^^^^^^^^^ + +interface ObjectExpression { + type: "ObjectExpression"; +>type : "ObjectExpression" +> : ^^^^^^^^^^^^^^^^^^ +} + +interface PropertyDefinition { + type: "PropertyDefinition"; +>type : "PropertyDefinition" +> : ^^^^^^^^^^^^^^^^^^^^ + + key: Expression; +>key : Expression +> : ^^^^^^^^^^ +} + +interface FunctionExpression { + type: "FunctionExpression"; +>type : "FunctionExpression" +> : ^^^^^^^^^^^^^^^^^^^^ + + body: BlockStatement; +>body : BlockStatement +> : ^^^^^^^^^^^^^^ +} + +interface NewExpression { + type: "NewExpression"; +>type : "NewExpression" +> : ^^^^^^^^^^^^^^^ + + callee: Expression; +>callee : Expression +> : ^^^^^^^^^^ + + arguments: Array; +>arguments : Expression[] +> : ^^^^^^^^^^^^ +} + +interface Identifier { + type: "Identifier"; +>type : "Identifier" +> : ^^^^^^^^^^^^ + + name: string; +>name : string +> : ^^^^^^ +} + +type Literal = SimpleLiteral | RegExpLiteral | BigIntLiteral; +>Literal : Literal +> : ^^^^^^^ + +interface SimpleLiteral { + type: "Literal"; +>type : "Literal" +> : ^^^^^^^^^ + + value: string | boolean | number | null; +>value : string | number | boolean | null +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} + +interface RegExpLiteral { + type: "Literal"; +>type : "Literal" +> : ^^^^^^^^^ + + value: RegExp; +>value : RegExp +> : ^^^^^^ +} + +interface BigIntLiteral { + type: "Literal"; +>type : "Literal" +> : ^^^^^^^^^ + + value: bigint; +>value : bigint +> : ^^^^^^ +} + +interface ArrowFunctionExpression { + type: "ArrowFunctionExpression"; +>type : "ArrowFunctionExpression" +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + + body: BlockStatement | Expression; +>body : Expression | BlockStatement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} + +interface ClassBody { + type: "ClassBody"; +>type : "ClassBody" +> : ^^^^^^^^^^^ + + body: Array; +>body : PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^ +} + +interface ClassExpression { + type: "ClassExpression"; +>type : "ClassExpression" +> : ^^^^^^^^^^^^^^^^^ + + body: ClassBody; +>body : ClassBody +> : ^^^^^^^^^ +} + +export function getNestedReturnStatements(node: Node): Array { +>getNestedReturnStatements : (node: Node) => Array +> : ^ ^^ ^^^^^ +>node : Node +> : ^^^^ + + const returnStatements: Array = []; +>returnStatements : ReturnStatement[] +> : ^^^^^^^^^^^^^^^^^ +>[] : never[] +> : ^^^^^^^ + + if (node.type === "ReturnStatement") { +>node.type === "ReturnStatement" : boolean +> : ^^^^^^^ +>node.type : "ArrowFunctionExpression" | "ClassExpression" | "FunctionExpression" | "Identifier" | "Literal" | "NewExpression" | "ObjectExpression" | "ClassBody" | "PropertyDefinition" | "BlockStatement" | "ReturnStatement" | "FunctionDeclaration" +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node : Node +> : ^^^^ +>type : "ArrowFunctionExpression" | "ClassExpression" | "FunctionExpression" | "Identifier" | "Literal" | "NewExpression" | "ObjectExpression" | "ClassBody" | "PropertyDefinition" | "BlockStatement" | "ReturnStatement" | "FunctionDeclaration" +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>"ReturnStatement" : "ReturnStatement" +> : ^^^^^^^^^^^^^^^^^ + + returnStatements.push(node); +>returnStatements.push(node) : number +> : ^^^^^^ +>returnStatements.push : (...items: ReturnStatement[]) => number +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>returnStatements : ReturnStatement[] +> : ^^^^^^^^^^^^^^^^^ +>push : (...items: ReturnStatement[]) => number +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>node : ReturnStatement +> : ^^^^^^^^^^^^^^^ + } + + if ("body" in node && node.body !== undefined && node.body !== null) { +>"body" in node && node.body !== undefined && node.body !== null : boolean +> : ^^^^^^^ +>"body" in node && node.body !== undefined : boolean +> : ^^^^^^^ +>"body" in node : boolean +> : ^^^^^^^ +>"body" : "body" +> : ^^^^^^ +>node : Node +> : ^^^^ +>node.body !== undefined : boolean +> : ^^^^^^^ +>node.body : ClassBody | Expression | BlockStatement | Statement[] | PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node : ClassBody | ArrowFunctionExpression | ClassExpression | FunctionExpression | FunctionDeclaration | BlockStatement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>body : ClassBody | Expression | BlockStatement | Statement[] | PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +>node.body !== null : boolean +> : ^^^^^^^ +>node.body : ClassBody | Expression | BlockStatement | Statement[] | PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node : ClassBody | ArrowFunctionExpression | ClassExpression | FunctionExpression | FunctionDeclaration | BlockStatement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>body : ClassBody | Expression | BlockStatement | Statement[] | PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Array.isArray(node.body) +>Array.isArray(node.body) ? node.body.forEach((x) => { returnStatements.push(...getNestedReturnStatements(x)); }) : returnStatements.push(...getNestedReturnStatements(node.body)) : number | void +> : ^^^^^^^^^^^^^ +>Array.isArray(node.body) : boolean +> : ^^^^^^^ +>Array.isArray : (arg: any) => arg is any[] +> : ^ ^^ ^^^^^ +>Array : ArrayConstructor +> : ^^^^^^^^^^^^^^^^ +>isArray : (arg: any) => arg is any[] +> : ^ ^^ ^^^^^ +>node.body : ClassBody | Expression | BlockStatement | Statement[] | PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node : ClassBody | ArrowFunctionExpression | ClassExpression | FunctionExpression | FunctionDeclaration | BlockStatement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>body : ClassBody | Expression | BlockStatement | Statement[] | PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ? node.body.forEach((x) => { +>node.body.forEach((x) => { returnStatements.push(...getNestedReturnStatements(x)); }) : void +> : ^^^^ +>node.body.forEach : ((callbackfn: (value: Statement, index: number, array: Statement[]) => void, thisArg?: any) => void) | ((callbackfn: (value: PropertyDefinition, index: number, array: PropertyDefinition[]) => void, thisArg?: any) => void) +> : ^^ ^^^ ^^^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ^ +>node.body : Statement[] | PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node : ClassBody | ArrowFunctionExpression | ClassExpression | FunctionExpression | FunctionDeclaration | BlockStatement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>body : Statement[] | PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>forEach : ((callbackfn: (value: Statement, index: number, array: Statement[]) => void, thisArg?: any) => void) | ((callbackfn: (value: PropertyDefinition, index: number, array: PropertyDefinition[]) => void, thisArg?: any) => void) +> : ^^ ^^^ ^^^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ^ +>(x) => { returnStatements.push(...getNestedReturnStatements(x)); } : (x: PropertyDefinition | Statement) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>x : PropertyDefinition | Statement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + returnStatements.push(...getNestedReturnStatements(x)); +>returnStatements.push(...getNestedReturnStatements(x)) : number +> : ^^^^^^ +>returnStatements.push : (...items: ReturnStatement[]) => number +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>returnStatements : ReturnStatement[] +> : ^^^^^^^^^^^^^^^^^ +>push : (...items: ReturnStatement[]) => number +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>...getNestedReturnStatements(x) : ReturnStatement +> : ^^^^^^^^^^^^^^^ +>getNestedReturnStatements(x) : ReturnStatement[] +> : ^^^^^^^^^^^^^^^^^ +>getNestedReturnStatements : (node: Node) => Array +> : ^ ^^ ^^^^^ +>x : PropertyDefinition | Statement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + }) + : returnStatements.push(...getNestedReturnStatements(node.body)); +>returnStatements.push(...getNestedReturnStatements(node.body)) : number +> : ^^^^^^ +>returnStatements.push : (...items: ReturnStatement[]) => number +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>returnStatements : ReturnStatement[] +> : ^^^^^^^^^^^^^^^^^ +>push : (...items: ReturnStatement[]) => number +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>...getNestedReturnStatements(node.body) : ReturnStatement +> : ^^^^^^^^^^^^^^^ +>getNestedReturnStatements(node.body) : ReturnStatement[] +> : ^^^^^^^^^^^^^^^^^ +>getNestedReturnStatements : (node: Node) => Array +> : ^ ^^ ^^^^^ +>node.body : ClassBody | Expression | BlockStatement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node : ClassBody | ArrowFunctionExpression | ClassExpression | FunctionExpression | FunctionDeclaration | BlockStatement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>body : ClassBody | Expression | BlockStatement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + } + + return returnStatements; +>returnStatements : ReturnStatement[] +> : ^^^^^^^^^^^^^^^^^ +} + diff --git a/tests/baselines/reference/narrowingUnionToUnion3.symbols b/tests/baselines/reference/narrowingUnionToUnion3.symbols new file mode 100644 index 0000000000000..6c45e95fee931 --- /dev/null +++ b/tests/baselines/reference/narrowingUnionToUnion3.symbols @@ -0,0 +1,273 @@ +//// [tests/cases/compiler/narrowingUnionToUnion3.ts] //// + +=== narrowingUnionToUnion3.ts === +interface NodeMap { +>NodeMap : Symbol(NodeMap, Decl(narrowingUnionToUnion3.ts, 0, 0)) + + ClassBody: ClassBody; +>ClassBody : Symbol(NodeMap.ClassBody, Decl(narrowingUnionToUnion3.ts, 0, 19)) +>ClassBody : Symbol(ClassBody, Decl(narrowingUnionToUnion3.ts, 70, 1)) + + Expression: Expression; +>Expression : Symbol(NodeMap.Expression, Decl(narrowingUnionToUnion3.ts, 1, 23)) +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion3.ts, 38, 1)) + + Function: Function; +>Function : Symbol(NodeMap.Function, Decl(narrowingUnionToUnion3.ts, 2, 25)) +>Function : Symbol(Function, Decl(narrowingUnionToUnion3.ts, 8, 35)) + + PropertyDefinition: PropertyDefinition; +>PropertyDefinition : Symbol(NodeMap.PropertyDefinition, Decl(narrowingUnionToUnion3.ts, 3, 21)) +>PropertyDefinition : Symbol(PropertyDefinition, Decl(narrowingUnionToUnion3.ts, 44, 1)) + + Statement: Statement; +>Statement : Symbol(NodeMap.Statement, Decl(narrowingUnionToUnion3.ts, 4, 41)) +>Statement : Symbol(Statement, Decl(narrowingUnionToUnion3.ts, 13, 28)) +} + +type Node = NodeMap[keyof NodeMap]; +>Node : Symbol(Node, Decl(narrowingUnionToUnion3.ts, 6, 1)) +>NodeMap : Symbol(NodeMap, Decl(narrowingUnionToUnion3.ts, 0, 0)) +>NodeMap : Symbol(NodeMap, Decl(narrowingUnionToUnion3.ts, 0, 0)) + +type Function = +>Function : Symbol(Function, Decl(narrowingUnionToUnion3.ts, 8, 35)) + + | FunctionDeclaration +>FunctionDeclaration : Symbol(FunctionDeclaration, Decl(narrowingUnionToUnion3.ts, 24, 1)) + + | FunctionExpression +>FunctionExpression : Symbol(FunctionExpression, Decl(narrowingUnionToUnion3.ts, 49, 1)) + + | ArrowFunctionExpression; +>ArrowFunctionExpression : Symbol(ArrowFunctionExpression, Decl(narrowingUnionToUnion3.ts, 65, 1)) + +type Statement = BlockStatement | ReturnStatement; +>Statement : Symbol(Statement, Decl(narrowingUnionToUnion3.ts, 13, 28)) +>BlockStatement : Symbol(BlockStatement, Decl(narrowingUnionToUnion3.ts, 15, 50)) +>ReturnStatement : Symbol(ReturnStatement, Decl(narrowingUnionToUnion3.ts, 20, 1)) + +interface BlockStatement { +>BlockStatement : Symbol(BlockStatement, Decl(narrowingUnionToUnion3.ts, 15, 50)) + + type: "BlockStatement"; +>type : Symbol(BlockStatement.type, Decl(narrowingUnionToUnion3.ts, 17, 26)) + + body: Statement[]; +>body : Symbol(BlockStatement.body, Decl(narrowingUnionToUnion3.ts, 18, 25)) +>Statement : Symbol(Statement, Decl(narrowingUnionToUnion3.ts, 13, 28)) +} + +interface ReturnStatement { +>ReturnStatement : Symbol(ReturnStatement, Decl(narrowingUnionToUnion3.ts, 20, 1)) + + type: "ReturnStatement"; +>type : Symbol(ReturnStatement.type, Decl(narrowingUnionToUnion3.ts, 22, 27)) +} + +interface FunctionDeclaration { +>FunctionDeclaration : Symbol(FunctionDeclaration, Decl(narrowingUnionToUnion3.ts, 24, 1)) + + type: "FunctionDeclaration"; +>type : Symbol(FunctionDeclaration.type, Decl(narrowingUnionToUnion3.ts, 26, 31)) + + body: BlockStatement; +>body : Symbol(FunctionDeclaration.body, Decl(narrowingUnionToUnion3.ts, 27, 30)) +>BlockStatement : Symbol(BlockStatement, Decl(narrowingUnionToUnion3.ts, 15, 50)) +} + +interface ExpressionMap { +>ExpressionMap : Symbol(ExpressionMap, Decl(narrowingUnionToUnion3.ts, 29, 1)) + + ArrowFunctionExpression: ArrowFunctionExpression; +>ArrowFunctionExpression : Symbol(ExpressionMap.ArrowFunctionExpression, Decl(narrowingUnionToUnion3.ts, 31, 25)) +>ArrowFunctionExpression : Symbol(ArrowFunctionExpression, Decl(narrowingUnionToUnion3.ts, 65, 1)) + + ClassExpression: ClassExpression; +>ClassExpression : Symbol(ExpressionMap.ClassExpression, Decl(narrowingUnionToUnion3.ts, 32, 51)) +>ClassExpression : Symbol(ClassExpression, Decl(narrowingUnionToUnion3.ts, 75, 1)) + + FunctionExpression: FunctionExpression; +>FunctionExpression : Symbol(ExpressionMap.FunctionExpression, Decl(narrowingUnionToUnion3.ts, 33, 35)) +>FunctionExpression : Symbol(FunctionExpression, Decl(narrowingUnionToUnion3.ts, 49, 1)) + + Identifier: Identifier; +>Identifier : Symbol(ExpressionMap.Identifier, Decl(narrowingUnionToUnion3.ts, 34, 41)) +>Identifier : Symbol(Identifier, Decl(narrowingUnionToUnion3.ts, 60, 1)) + + NewExpression: NewExpression; +>NewExpression : Symbol(ExpressionMap.NewExpression, Decl(narrowingUnionToUnion3.ts, 35, 25)) +>NewExpression : Symbol(NewExpression, Decl(narrowingUnionToUnion3.ts, 54, 1)) + + ObjectExpression: ObjectExpression; +>ObjectExpression : Symbol(ExpressionMap.ObjectExpression, Decl(narrowingUnionToUnion3.ts, 36, 31)) +>ObjectExpression : Symbol(ObjectExpression, Decl(narrowingUnionToUnion3.ts, 40, 53)) +} + +type Expression = ExpressionMap[keyof ExpressionMap]; +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion3.ts, 38, 1)) +>ExpressionMap : Symbol(ExpressionMap, Decl(narrowingUnionToUnion3.ts, 29, 1)) +>ExpressionMap : Symbol(ExpressionMap, Decl(narrowingUnionToUnion3.ts, 29, 1)) + +interface ObjectExpression { +>ObjectExpression : Symbol(ObjectExpression, Decl(narrowingUnionToUnion3.ts, 40, 53)) + + type: "ObjectExpression"; +>type : Symbol(ObjectExpression.type, Decl(narrowingUnionToUnion3.ts, 42, 28)) +} + +interface PropertyDefinition { +>PropertyDefinition : Symbol(PropertyDefinition, Decl(narrowingUnionToUnion3.ts, 44, 1)) + + type: "PropertyDefinition"; +>type : Symbol(PropertyDefinition.type, Decl(narrowingUnionToUnion3.ts, 46, 30)) + + key: Expression; +>key : Symbol(PropertyDefinition.key, Decl(narrowingUnionToUnion3.ts, 47, 29)) +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion3.ts, 38, 1)) +} + +interface FunctionExpression { +>FunctionExpression : Symbol(FunctionExpression, Decl(narrowingUnionToUnion3.ts, 49, 1)) + + type: "FunctionExpression"; +>type : Symbol(FunctionExpression.type, Decl(narrowingUnionToUnion3.ts, 51, 30)) + + body: BlockStatement; +>body : Symbol(FunctionExpression.body, Decl(narrowingUnionToUnion3.ts, 52, 29)) +>BlockStatement : Symbol(BlockStatement, Decl(narrowingUnionToUnion3.ts, 15, 50)) +} + +interface NewExpression { +>NewExpression : Symbol(NewExpression, Decl(narrowingUnionToUnion3.ts, 54, 1)) + + type: "NewExpression"; +>type : Symbol(NewExpression.type, Decl(narrowingUnionToUnion3.ts, 56, 25)) + + callee: Expression; +>callee : Symbol(NewExpression.callee, Decl(narrowingUnionToUnion3.ts, 57, 24)) +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion3.ts, 38, 1)) + + arguments: Array; +>arguments : Symbol(NewExpression.arguments, Decl(narrowingUnionToUnion3.ts, 58, 21)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion3.ts, 38, 1)) +} + +interface Identifier { +>Identifier : Symbol(Identifier, Decl(narrowingUnionToUnion3.ts, 60, 1)) + + type: "Identifier"; +>type : Symbol(Identifier.type, Decl(narrowingUnionToUnion3.ts, 62, 22)) + + name: string; +>name : Symbol(Identifier.name, Decl(narrowingUnionToUnion3.ts, 63, 21)) +} + +interface ArrowFunctionExpression { +>ArrowFunctionExpression : Symbol(ArrowFunctionExpression, Decl(narrowingUnionToUnion3.ts, 65, 1)) + + type: "ArrowFunctionExpression"; +>type : Symbol(ArrowFunctionExpression.type, Decl(narrowingUnionToUnion3.ts, 67, 35)) + + body: BlockStatement | Expression; +>body : Symbol(ArrowFunctionExpression.body, Decl(narrowingUnionToUnion3.ts, 68, 34)) +>BlockStatement : Symbol(BlockStatement, Decl(narrowingUnionToUnion3.ts, 15, 50)) +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion3.ts, 38, 1)) +} + +interface ClassBody { +>ClassBody : Symbol(ClassBody, Decl(narrowingUnionToUnion3.ts, 70, 1)) + + type: "ClassBody"; +>type : Symbol(ClassBody.type, Decl(narrowingUnionToUnion3.ts, 72, 21)) + + body: Array; +>body : Symbol(ClassBody.body, Decl(narrowingUnionToUnion3.ts, 73, 20)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>PropertyDefinition : Symbol(PropertyDefinition, Decl(narrowingUnionToUnion3.ts, 44, 1)) +} + +interface ClassExpression { +>ClassExpression : Symbol(ClassExpression, Decl(narrowingUnionToUnion3.ts, 75, 1)) + + type: "ClassExpression"; +>type : Symbol(ClassExpression.type, Decl(narrowingUnionToUnion3.ts, 77, 27)) + + body: ClassBody; +>body : Symbol(ClassExpression.body, Decl(narrowingUnionToUnion3.ts, 78, 26)) +>ClassBody : Symbol(ClassBody, Decl(narrowingUnionToUnion3.ts, 70, 1)) +} + +export function getNestedReturnStatements(node: Node): Array { +>getNestedReturnStatements : Symbol(getNestedReturnStatements, Decl(narrowingUnionToUnion3.ts, 80, 1)) +>node : Symbol(node, Decl(narrowingUnionToUnion3.ts, 82, 42)) +>Node : Symbol(Node, Decl(narrowingUnionToUnion3.ts, 6, 1)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>ReturnStatement : Symbol(ReturnStatement, Decl(narrowingUnionToUnion3.ts, 20, 1)) + + const returnStatements: Array = []; +>returnStatements : Symbol(returnStatements, Decl(narrowingUnionToUnion3.ts, 83, 7)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>ReturnStatement : Symbol(ReturnStatement, Decl(narrowingUnionToUnion3.ts, 20, 1)) + + if (node.type === "ReturnStatement") { +>node.type : Symbol(type, Decl(narrowingUnionToUnion3.ts, 72, 21), Decl(narrowingUnionToUnion3.ts, 67, 35), Decl(narrowingUnionToUnion3.ts, 77, 27), Decl(narrowingUnionToUnion3.ts, 51, 30), Decl(narrowingUnionToUnion3.ts, 62, 22) ... and 6 more) +>node : Symbol(node, Decl(narrowingUnionToUnion3.ts, 82, 42)) +>type : Symbol(type, Decl(narrowingUnionToUnion3.ts, 72, 21), Decl(narrowingUnionToUnion3.ts, 67, 35), Decl(narrowingUnionToUnion3.ts, 77, 27), Decl(narrowingUnionToUnion3.ts, 51, 30), Decl(narrowingUnionToUnion3.ts, 62, 22) ... and 6 more) + + returnStatements.push(node); +>returnStatements.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>returnStatements : Symbol(returnStatements, Decl(narrowingUnionToUnion3.ts, 83, 7)) +>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>node : Symbol(node, Decl(narrowingUnionToUnion3.ts, 82, 42)) + } + + if ("body" in node && node.body !== undefined && node.body !== null) { +>node : Symbol(node, Decl(narrowingUnionToUnion3.ts, 82, 42)) +>node.body : Symbol(body, Decl(narrowingUnionToUnion3.ts, 73, 20), Decl(narrowingUnionToUnion3.ts, 68, 34), Decl(narrowingUnionToUnion3.ts, 78, 26), Decl(narrowingUnionToUnion3.ts, 52, 29), Decl(narrowingUnionToUnion3.ts, 27, 30) ... and 1 more) +>node : Symbol(node, Decl(narrowingUnionToUnion3.ts, 82, 42)) +>body : Symbol(body, Decl(narrowingUnionToUnion3.ts, 73, 20), Decl(narrowingUnionToUnion3.ts, 68, 34), Decl(narrowingUnionToUnion3.ts, 78, 26), Decl(narrowingUnionToUnion3.ts, 52, 29), Decl(narrowingUnionToUnion3.ts, 27, 30) ... and 1 more) +>undefined : Symbol(undefined) +>node.body : Symbol(body, Decl(narrowingUnionToUnion3.ts, 73, 20), Decl(narrowingUnionToUnion3.ts, 68, 34), Decl(narrowingUnionToUnion3.ts, 78, 26), Decl(narrowingUnionToUnion3.ts, 52, 29), Decl(narrowingUnionToUnion3.ts, 27, 30) ... and 1 more) +>node : Symbol(node, Decl(narrowingUnionToUnion3.ts, 82, 42)) +>body : Symbol(body, Decl(narrowingUnionToUnion3.ts, 73, 20), Decl(narrowingUnionToUnion3.ts, 68, 34), Decl(narrowingUnionToUnion3.ts, 78, 26), Decl(narrowingUnionToUnion3.ts, 52, 29), Decl(narrowingUnionToUnion3.ts, 27, 30) ... and 1 more) + + Array.isArray(node.body) +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>node.body : Symbol(body, Decl(narrowingUnionToUnion3.ts, 73, 20), Decl(narrowingUnionToUnion3.ts, 68, 34), Decl(narrowingUnionToUnion3.ts, 78, 26), Decl(narrowingUnionToUnion3.ts, 52, 29), Decl(narrowingUnionToUnion3.ts, 27, 30) ... and 1 more) +>node : Symbol(node, Decl(narrowingUnionToUnion3.ts, 82, 42)) +>body : Symbol(body, Decl(narrowingUnionToUnion3.ts, 73, 20), Decl(narrowingUnionToUnion3.ts, 68, 34), Decl(narrowingUnionToUnion3.ts, 78, 26), Decl(narrowingUnionToUnion3.ts, 52, 29), Decl(narrowingUnionToUnion3.ts, 27, 30) ... and 1 more) + + ? node.body.forEach((x) => { +>node.body.forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>node.body : Symbol(body, Decl(narrowingUnionToUnion3.ts, 73, 20), Decl(narrowingUnionToUnion3.ts, 68, 34), Decl(narrowingUnionToUnion3.ts, 78, 26), Decl(narrowingUnionToUnion3.ts, 52, 29), Decl(narrowingUnionToUnion3.ts, 27, 30) ... and 1 more) +>node : Symbol(node, Decl(narrowingUnionToUnion3.ts, 82, 42)) +>body : Symbol(body, Decl(narrowingUnionToUnion3.ts, 73, 20), Decl(narrowingUnionToUnion3.ts, 68, 34), Decl(narrowingUnionToUnion3.ts, 78, 26), Decl(narrowingUnionToUnion3.ts, 52, 29), Decl(narrowingUnionToUnion3.ts, 27, 30) ... and 1 more) +>forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(narrowingUnionToUnion3.ts, 91, 27)) + + returnStatements.push(...getNestedReturnStatements(x)); +>returnStatements.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>returnStatements : Symbol(returnStatements, Decl(narrowingUnionToUnion3.ts, 83, 7)) +>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>getNestedReturnStatements : Symbol(getNestedReturnStatements, Decl(narrowingUnionToUnion3.ts, 80, 1)) +>x : Symbol(x, Decl(narrowingUnionToUnion3.ts, 91, 27)) + + }) + : returnStatements.push(...getNestedReturnStatements(node.body)); +>returnStatements.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>returnStatements : Symbol(returnStatements, Decl(narrowingUnionToUnion3.ts, 83, 7)) +>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>getNestedReturnStatements : Symbol(getNestedReturnStatements, Decl(narrowingUnionToUnion3.ts, 80, 1)) +>node.body : Symbol(body, Decl(narrowingUnionToUnion3.ts, 73, 20), Decl(narrowingUnionToUnion3.ts, 68, 34), Decl(narrowingUnionToUnion3.ts, 78, 26), Decl(narrowingUnionToUnion3.ts, 52, 29), Decl(narrowingUnionToUnion3.ts, 27, 30) ... and 1 more) +>node : Symbol(node, Decl(narrowingUnionToUnion3.ts, 82, 42)) +>body : Symbol(body, Decl(narrowingUnionToUnion3.ts, 73, 20), Decl(narrowingUnionToUnion3.ts, 68, 34), Decl(narrowingUnionToUnion3.ts, 78, 26), Decl(narrowingUnionToUnion3.ts, 52, 29), Decl(narrowingUnionToUnion3.ts, 27, 30) ... and 1 more) + } + + return returnStatements; +>returnStatements : Symbol(returnStatements, Decl(narrowingUnionToUnion3.ts, 83, 7)) +} + diff --git a/tests/baselines/reference/narrowingUnionToUnion3.types b/tests/baselines/reference/narrowingUnionToUnion3.types new file mode 100644 index 0000000000000..35d92a739affd --- /dev/null +++ b/tests/baselines/reference/narrowingUnionToUnion3.types @@ -0,0 +1,327 @@ +//// [tests/cases/compiler/narrowingUnionToUnion3.ts] //// + +=== narrowingUnionToUnion3.ts === +interface NodeMap { + ClassBody: ClassBody; +>ClassBody : ClassBody +> : ^^^^^^^^^ + + Expression: Expression; +>Expression : Expression +> : ^^^^^^^^^^ + + Function: Function; +>Function : Function +> : ^^^^^^^^ + + PropertyDefinition: PropertyDefinition; +>PropertyDefinition : PropertyDefinition +> : ^^^^^^^^^^^^^^^^^^ + + Statement: Statement; +>Statement : Statement +> : ^^^^^^^^^ +} + +type Node = NodeMap[keyof NodeMap]; +>Node : Node +> : ^^^^ + +type Function = +>Function : Function +> : ^^^^^^^^ + + | FunctionDeclaration + | FunctionExpression + | ArrowFunctionExpression; + +type Statement = BlockStatement | ReturnStatement; +>Statement : Statement +> : ^^^^^^^^^ + +interface BlockStatement { + type: "BlockStatement"; +>type : "BlockStatement" +> : ^^^^^^^^^^^^^^^^ + + body: Statement[]; +>body : Statement[] +> : ^^^^^^^^^^^ +} + +interface ReturnStatement { + type: "ReturnStatement"; +>type : "ReturnStatement" +> : ^^^^^^^^^^^^^^^^^ +} + +interface FunctionDeclaration { + type: "FunctionDeclaration"; +>type : "FunctionDeclaration" +> : ^^^^^^^^^^^^^^^^^^^^^ + + body: BlockStatement; +>body : BlockStatement +> : ^^^^^^^^^^^^^^ +} + +interface ExpressionMap { + ArrowFunctionExpression: ArrowFunctionExpression; +>ArrowFunctionExpression : ArrowFunctionExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^ + + ClassExpression: ClassExpression; +>ClassExpression : ClassExpression +> : ^^^^^^^^^^^^^^^ + + FunctionExpression: FunctionExpression; +>FunctionExpression : FunctionExpression +> : ^^^^^^^^^^^^^^^^^^ + + Identifier: Identifier; +>Identifier : Identifier +> : ^^^^^^^^^^ + + NewExpression: NewExpression; +>NewExpression : NewExpression +> : ^^^^^^^^^^^^^ + + ObjectExpression: ObjectExpression; +>ObjectExpression : ObjectExpression +> : ^^^^^^^^^^^^^^^^ +} + +type Expression = ExpressionMap[keyof ExpressionMap]; +>Expression : Expression +> : ^^^^^^^^^^ + +interface ObjectExpression { + type: "ObjectExpression"; +>type : "ObjectExpression" +> : ^^^^^^^^^^^^^^^^^^ +} + +interface PropertyDefinition { + type: "PropertyDefinition"; +>type : "PropertyDefinition" +> : ^^^^^^^^^^^^^^^^^^^^ + + key: Expression; +>key : Expression +> : ^^^^^^^^^^ +} + +interface FunctionExpression { + type: "FunctionExpression"; +>type : "FunctionExpression" +> : ^^^^^^^^^^^^^^^^^^^^ + + body: BlockStatement; +>body : BlockStatement +> : ^^^^^^^^^^^^^^ +} + +interface NewExpression { + type: "NewExpression"; +>type : "NewExpression" +> : ^^^^^^^^^^^^^^^ + + callee: Expression; +>callee : Expression +> : ^^^^^^^^^^ + + arguments: Array; +>arguments : Expression[] +> : ^^^^^^^^^^^^ +} + +interface Identifier { + type: "Identifier"; +>type : "Identifier" +> : ^^^^^^^^^^^^ + + name: string; +>name : string +> : ^^^^^^ +} + +interface ArrowFunctionExpression { + type: "ArrowFunctionExpression"; +>type : "ArrowFunctionExpression" +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + + body: BlockStatement | Expression; +>body : Expression | BlockStatement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} + +interface ClassBody { + type: "ClassBody"; +>type : "ClassBody" +> : ^^^^^^^^^^^ + + body: Array; +>body : PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^ +} + +interface ClassExpression { + type: "ClassExpression"; +>type : "ClassExpression" +> : ^^^^^^^^^^^^^^^^^ + + body: ClassBody; +>body : ClassBody +> : ^^^^^^^^^ +} + +export function getNestedReturnStatements(node: Node): Array { +>getNestedReturnStatements : (node: Node) => Array +> : ^ ^^ ^^^^^ +>node : Node +> : ^^^^ + + const returnStatements: Array = []; +>returnStatements : ReturnStatement[] +> : ^^^^^^^^^^^^^^^^^ +>[] : never[] +> : ^^^^^^^ + + if (node.type === "ReturnStatement") { +>node.type === "ReturnStatement" : boolean +> : ^^^^^^^ +>node.type : "ArrowFunctionExpression" | "ClassExpression" | "FunctionExpression" | "Identifier" | "NewExpression" | "ObjectExpression" | "ClassBody" | "PropertyDefinition" | "BlockStatement" | "ReturnStatement" | "FunctionDeclaration" +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node : Node +> : ^^^^ +>type : "ArrowFunctionExpression" | "ClassExpression" | "FunctionExpression" | "Identifier" | "NewExpression" | "ObjectExpression" | "ClassBody" | "PropertyDefinition" | "BlockStatement" | "ReturnStatement" | "FunctionDeclaration" +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>"ReturnStatement" : "ReturnStatement" +> : ^^^^^^^^^^^^^^^^^ + + returnStatements.push(node); +>returnStatements.push(node) : number +> : ^^^^^^ +>returnStatements.push : (...items: ReturnStatement[]) => number +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>returnStatements : ReturnStatement[] +> : ^^^^^^^^^^^^^^^^^ +>push : (...items: ReturnStatement[]) => number +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>node : ReturnStatement +> : ^^^^^^^^^^^^^^^ + } + + if ("body" in node && node.body !== undefined && node.body !== null) { +>"body" in node && node.body !== undefined && node.body !== null : boolean +> : ^^^^^^^ +>"body" in node && node.body !== undefined : boolean +> : ^^^^^^^ +>"body" in node : boolean +> : ^^^^^^^ +>"body" : "body" +> : ^^^^^^ +>node : Node +> : ^^^^ +>node.body !== undefined : boolean +> : ^^^^^^^ +>node.body : ClassBody | Expression | BlockStatement | Statement[] | PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node : ClassBody | ArrowFunctionExpression | ClassExpression | FunctionExpression | FunctionDeclaration | BlockStatement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>body : ClassBody | Expression | BlockStatement | Statement[] | PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ +>node.body !== null : boolean +> : ^^^^^^^ +>node.body : ClassBody | Expression | BlockStatement | Statement[] | PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node : ClassBody | ArrowFunctionExpression | ClassExpression | FunctionExpression | FunctionDeclaration | BlockStatement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>body : ClassBody | Expression | BlockStatement | Statement[] | PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Array.isArray(node.body) +>Array.isArray(node.body) ? node.body.forEach((x) => { returnStatements.push(...getNestedReturnStatements(x)); }) : returnStatements.push(...getNestedReturnStatements(node.body)) : number | void +> : ^^^^^^^^^^^^^ +>Array.isArray(node.body) : boolean +> : ^^^^^^^ +>Array.isArray : (arg: any) => arg is any[] +> : ^ ^^ ^^^^^ +>Array : ArrayConstructor +> : ^^^^^^^^^^^^^^^^ +>isArray : (arg: any) => arg is any[] +> : ^ ^^ ^^^^^ +>node.body : ClassBody | Expression | BlockStatement | Statement[] | PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node : ClassBody | ArrowFunctionExpression | ClassExpression | FunctionExpression | FunctionDeclaration | BlockStatement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>body : ClassBody | Expression | BlockStatement | Statement[] | PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ? node.body.forEach((x) => { +>node.body.forEach((x) => { returnStatements.push(...getNestedReturnStatements(x)); }) : void +> : ^^^^ +>node.body.forEach : ((callbackfn: (value: Statement, index: number, array: Statement[]) => void, thisArg?: any) => void) | ((callbackfn: (value: PropertyDefinition, index: number, array: PropertyDefinition[]) => void, thisArg?: any) => void) +> : ^^ ^^^ ^^^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ^ +>node.body : Statement[] | PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node : ClassBody | ArrowFunctionExpression | ClassExpression | FunctionExpression | FunctionDeclaration | BlockStatement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>body : Statement[] | PropertyDefinition[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>forEach : ((callbackfn: (value: Statement, index: number, array: Statement[]) => void, thisArg?: any) => void) | ((callbackfn: (value: PropertyDefinition, index: number, array: PropertyDefinition[]) => void, thisArg?: any) => void) +> : ^^ ^^^ ^^^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ^ +>(x) => { returnStatements.push(...getNestedReturnStatements(x)); } : (x: PropertyDefinition | Statement) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>x : PropertyDefinition | Statement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + returnStatements.push(...getNestedReturnStatements(x)); +>returnStatements.push(...getNestedReturnStatements(x)) : number +> : ^^^^^^ +>returnStatements.push : (...items: ReturnStatement[]) => number +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>returnStatements : ReturnStatement[] +> : ^^^^^^^^^^^^^^^^^ +>push : (...items: ReturnStatement[]) => number +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>...getNestedReturnStatements(x) : ReturnStatement +> : ^^^^^^^^^^^^^^^ +>getNestedReturnStatements(x) : ReturnStatement[] +> : ^^^^^^^^^^^^^^^^^ +>getNestedReturnStatements : (node: Node) => Array +> : ^ ^^ ^^^^^ +>x : PropertyDefinition | Statement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + }) + : returnStatements.push(...getNestedReturnStatements(node.body)); +>returnStatements.push(...getNestedReturnStatements(node.body)) : number +> : ^^^^^^ +>returnStatements.push : (...items: ReturnStatement[]) => number +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>returnStatements : ReturnStatement[] +> : ^^^^^^^^^^^^^^^^^ +>push : (...items: ReturnStatement[]) => number +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>...getNestedReturnStatements(node.body) : ReturnStatement +> : ^^^^^^^^^^^^^^^ +>getNestedReturnStatements(node.body) : ReturnStatement[] +> : ^^^^^^^^^^^^^^^^^ +>getNestedReturnStatements : (node: Node) => Array +> : ^ ^^ ^^^^^ +>node.body : ClassBody | Expression | BlockStatement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node : ClassBody | ArrowFunctionExpression | ClassExpression | FunctionExpression | FunctionDeclaration | BlockStatement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>body : ClassBody | Expression | BlockStatement +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + } + + return returnStatements; +>returnStatements : ReturnStatement[] +> : ^^^^^^^^^^^^^^^^^ +} + diff --git a/tests/cases/compiler/narrowingUnionToUnion2.ts b/tests/cases/compiler/narrowingUnionToUnion2.ts new file mode 100644 index 0000000000000..0d42e2cd65882 --- /dev/null +++ b/tests/cases/compiler/narrowingUnionToUnion2.ts @@ -0,0 +1,120 @@ +// @strict: true +// @noEmit: true + +interface NodeMap { + ClassBody: ClassBody; + Expression: Expression; + Function: Function; + PropertyDefinition: PropertyDefinition; + Statement: Statement; +} + +type Node = NodeMap[keyof NodeMap]; + +type Function = + | FunctionDeclaration + | FunctionExpression + | ArrowFunctionExpression; + +type Statement = BlockStatement | ReturnStatement; + +interface BlockStatement { + type: "BlockStatement"; + body: Statement[]; +} + +interface ReturnStatement { + type: "ReturnStatement"; +} + +interface FunctionDeclaration { + type: "FunctionDeclaration"; + body: BlockStatement; +} + +interface ExpressionMap { + ArrowFunctionExpression: ArrowFunctionExpression; + ClassExpression: ClassExpression; + FunctionExpression: FunctionExpression; + Identifier: Identifier; + Literal: Literal; + NewExpression: NewExpression; + ObjectExpression: ObjectExpression; +} + +type Expression = ExpressionMap[keyof ExpressionMap]; + +interface ObjectExpression { + type: "ObjectExpression"; +} + +interface PropertyDefinition { + type: "PropertyDefinition"; + key: Expression; +} + +interface FunctionExpression { + type: "FunctionExpression"; + body: BlockStatement; +} + +interface NewExpression { + type: "NewExpression"; + callee: Expression; + arguments: Array; +} + +interface Identifier { + type: "Identifier"; + name: string; +} + +type Literal = SimpleLiteral | RegExpLiteral | BigIntLiteral; + +interface SimpleLiteral { + type: "Literal"; + value: string | boolean | number | null; +} + +interface RegExpLiteral { + type: "Literal"; + value: RegExp; +} + +interface BigIntLiteral { + type: "Literal"; + value: bigint; +} + +interface ArrowFunctionExpression { + type: "ArrowFunctionExpression"; + body: BlockStatement | Expression; +} + +interface ClassBody { + type: "ClassBody"; + body: Array; +} + +interface ClassExpression { + type: "ClassExpression"; + body: ClassBody; +} + +export function getNestedReturnStatements(node: Node): Array { + const returnStatements: Array = []; + + if (node.type === "ReturnStatement") { + returnStatements.push(node); + } + + if ("body" in node && node.body !== undefined && node.body !== null) { + Array.isArray(node.body) + ? node.body.forEach((x) => { + returnStatements.push(...getNestedReturnStatements(x)); + }) + : returnStatements.push(...getNestedReturnStatements(node.body)); + } + + return returnStatements; +} diff --git a/tests/cases/compiler/narrowingUnionToUnion3.ts b/tests/cases/compiler/narrowingUnionToUnion3.ts new file mode 100644 index 0000000000000..a5e55c05655ad --- /dev/null +++ b/tests/cases/compiler/narrowingUnionToUnion3.ts @@ -0,0 +1,102 @@ +// @strict: true +// @noEmit: true + +interface NodeMap { + ClassBody: ClassBody; + Expression: Expression; + Function: Function; + PropertyDefinition: PropertyDefinition; + Statement: Statement; +} + +type Node = NodeMap[keyof NodeMap]; + +type Function = + | FunctionDeclaration + | FunctionExpression + | ArrowFunctionExpression; + +type Statement = BlockStatement | ReturnStatement; + +interface BlockStatement { + type: "BlockStatement"; + body: Statement[]; +} + +interface ReturnStatement { + type: "ReturnStatement"; +} + +interface FunctionDeclaration { + type: "FunctionDeclaration"; + body: BlockStatement; +} + +interface ExpressionMap { + ArrowFunctionExpression: ArrowFunctionExpression; + ClassExpression: ClassExpression; + FunctionExpression: FunctionExpression; + Identifier: Identifier; + NewExpression: NewExpression; + ObjectExpression: ObjectExpression; +} + +type Expression = ExpressionMap[keyof ExpressionMap]; + +interface ObjectExpression { + type: "ObjectExpression"; +} + +interface PropertyDefinition { + type: "PropertyDefinition"; + key: Expression; +} + +interface FunctionExpression { + type: "FunctionExpression"; + body: BlockStatement; +} + +interface NewExpression { + type: "NewExpression"; + callee: Expression; + arguments: Array; +} + +interface Identifier { + type: "Identifier"; + name: string; +} + +interface ArrowFunctionExpression { + type: "ArrowFunctionExpression"; + body: BlockStatement | Expression; +} + +interface ClassBody { + type: "ClassBody"; + body: Array; +} + +interface ClassExpression { + type: "ClassExpression"; + body: ClassBody; +} + +export function getNestedReturnStatements(node: Node): Array { + const returnStatements: Array = []; + + if (node.type === "ReturnStatement") { + returnStatements.push(node); + } + + if ("body" in node && node.body !== undefined && node.body !== null) { + Array.isArray(node.body) + ? node.body.forEach((x) => { + returnStatements.push(...getNestedReturnStatements(x)); + }) + : returnStatements.push(...getNestedReturnStatements(node.body)); + } + + return returnStatements; +} From 9850ba68a2a78335df887eb31347ded35f8fb84e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 20 Apr 2025 18:02:54 +0200 Subject: [PATCH 8/9] fix an extra case when the union has duplicated constituents with the sam key type --- src/compiler/checker.ts | 3 +- .../reference/narrowingUnionToUnion4.symbols | 427 ++++++++++++++++++ .../reference/narrowingUnionToUnion4.types | 406 +++++++++++++++++ .../cases/compiler/narrowingUnionToUnion4.ts | 165 +++++++ 4 files changed, 1000 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/narrowingUnionToUnion4.symbols create mode 100644 tests/baselines/reference/narrowingUnionToUnion4.types create mode 100644 tests/cases/compiler/narrowingUnionToUnion4.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b41fcb213ae09..93aec6dd7800e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29351,7 +29351,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (keyPropertyName) { // If a discriminant property is available, use only matching constituents to reduce the type. const discriminant = keyPropertyName && getTypeOfPropertyOfType(c, keyPropertyName); - if (discriminant && getConstituentTypeForKeyType(type as UnionType, discriminant) !== t) { + const keyTypeConstituent = discriminant && getConstituentTypeForKeyType(type as UnionType, discriminant); + if (keyTypeConstituent && keyTypeConstituent !== t) { return neverType; } } diff --git a/tests/baselines/reference/narrowingUnionToUnion4.symbols b/tests/baselines/reference/narrowingUnionToUnion4.symbols new file mode 100644 index 0000000000000..76106b4301c1a --- /dev/null +++ b/tests/baselines/reference/narrowingUnionToUnion4.symbols @@ -0,0 +1,427 @@ +//// [tests/cases/compiler/narrowingUnionToUnion4.ts] //// + +=== narrowingUnionToUnion4.ts === +const enum SyntaxKind { +>SyntaxKind : Symbol(SyntaxKind, Decl(narrowingUnionToUnion4.ts, 0, 0)) + + Identifier, +>Identifier : Symbol(SyntaxKind.Identifier, Decl(narrowingUnionToUnion4.ts, 0, 23)) + + PropertyAccessExpression, +>PropertyAccessExpression : Symbol(SyntaxKind.PropertyAccessExpression, Decl(narrowingUnionToUnion4.ts, 1, 13)) + + ParenthesizedExpression, +>ParenthesizedExpression : Symbol(SyntaxKind.ParenthesizedExpression, Decl(narrowingUnionToUnion4.ts, 2, 27)) + + ExpressionWithTypeArguments, +>ExpressionWithTypeArguments : Symbol(SyntaxKind.ExpressionWithTypeArguments, Decl(narrowingUnionToUnion4.ts, 3, 26)) + + NullKeyword, +>NullKeyword : Symbol(SyntaxKind.NullKeyword, Decl(narrowingUnionToUnion4.ts, 4, 30)) + + TrueKeyword, +>TrueKeyword : Symbol(SyntaxKind.TrueKeyword, Decl(narrowingUnionToUnion4.ts, 5, 14)) + + FalseKeyword, +>FalseKeyword : Symbol(SyntaxKind.FalseKeyword, Decl(narrowingUnionToUnion4.ts, 6, 14)) + + ThisKeyword, +>ThisKeyword : Symbol(SyntaxKind.ThisKeyword, Decl(narrowingUnionToUnion4.ts, 7, 15)) + + DeleteExpression, +>DeleteExpression : Symbol(SyntaxKind.DeleteExpression, Decl(narrowingUnionToUnion4.ts, 8, 14)) + + TypeOfExpression, +>TypeOfExpression : Symbol(SyntaxKind.TypeOfExpression, Decl(narrowingUnionToUnion4.ts, 9, 19)) + + VoidExpression, +>VoidExpression : Symbol(SyntaxKind.VoidExpression, Decl(narrowingUnionToUnion4.ts, 10, 19)) + + AwaitExpression, +>AwaitExpression : Symbol(SyntaxKind.AwaitExpression, Decl(narrowingUnionToUnion4.ts, 11, 17)) + + TypeAssertionExpression, +>TypeAssertionExpression : Symbol(SyntaxKind.TypeAssertionExpression, Decl(narrowingUnionToUnion4.ts, 12, 18)) + + NewExpression, +>NewExpression : Symbol(SyntaxKind.NewExpression, Decl(narrowingUnionToUnion4.ts, 13, 26)) + + NumericLiteral, +>NumericLiteral : Symbol(SyntaxKind.NumericLiteral, Decl(narrowingUnionToUnion4.ts, 14, 16)) + + StringLiteral, +>StringLiteral : Symbol(SyntaxKind.StringLiteral, Decl(narrowingUnionToUnion4.ts, 15, 17)) + + TemplateExpression, +>TemplateExpression : Symbol(SyntaxKind.TemplateExpression, Decl(narrowingUnionToUnion4.ts, 16, 16)) +} + +interface TypeNodeBase extends BaseNode { +>TypeNodeBase : Symbol(TypeNodeBase, Decl(narrowingUnionToUnion4.ts, 18, 1)) +>BaseNode : Symbol(BaseNode, Decl(narrowingUnionToUnion4.ts, 81, 22)) + + _typeNodeBrand: any; +>_typeNodeBrand : Symbol(TypeNodeBase._typeNodeBrand, Decl(narrowingUnionToUnion4.ts, 20, 41)) +} + +interface NullLiteral extends PrimaryExpressionBase, TypeNodeBase { +>NullLiteral : Symbol(NullLiteral, Decl(narrowingUnionToUnion4.ts, 22, 1)) +>PrimaryExpressionBase : Symbol(PrimaryExpressionBase, Decl(narrowingUnionToUnion4.ts, 105, 1)) +>TypeNodeBase : Symbol(TypeNodeBase, Decl(narrowingUnionToUnion4.ts, 18, 1)) + + kind: SyntaxKind.NullKeyword; +>kind : Symbol(NullLiteral.kind, Decl(narrowingUnionToUnion4.ts, 24, 67)) +>SyntaxKind : Symbol(SyntaxKind, Decl(narrowingUnionToUnion4.ts, 0, 0)) +>NullKeyword : Symbol(SyntaxKind.NullKeyword, Decl(narrowingUnionToUnion4.ts, 4, 30)) +} + +interface BooleanLiteral extends PrimaryExpressionBase, TypeNodeBase { +>BooleanLiteral : Symbol(BooleanLiteral, Decl(narrowingUnionToUnion4.ts, 26, 1)) +>PrimaryExpressionBase : Symbol(PrimaryExpressionBase, Decl(narrowingUnionToUnion4.ts, 105, 1)) +>TypeNodeBase : Symbol(TypeNodeBase, Decl(narrowingUnionToUnion4.ts, 18, 1)) + + kind: SyntaxKind.TrueKeyword | SyntaxKind.FalseKeyword; +>kind : Symbol(BooleanLiteral.kind, Decl(narrowingUnionToUnion4.ts, 28, 70)) +>SyntaxKind : Symbol(SyntaxKind, Decl(narrowingUnionToUnion4.ts, 0, 0)) +>TrueKeyword : Symbol(SyntaxKind.TrueKeyword, Decl(narrowingUnionToUnion4.ts, 5, 14)) +>SyntaxKind : Symbol(SyntaxKind, Decl(narrowingUnionToUnion4.ts, 0, 0)) +>FalseKeyword : Symbol(SyntaxKind.FalseKeyword, Decl(narrowingUnionToUnion4.ts, 6, 14)) +} + +interface ThisExpression extends PrimaryExpressionBase, TypeNodeBase { +>ThisExpression : Symbol(ThisExpression, Decl(narrowingUnionToUnion4.ts, 30, 1)) +>PrimaryExpressionBase : Symbol(PrimaryExpressionBase, Decl(narrowingUnionToUnion4.ts, 105, 1)) +>TypeNodeBase : Symbol(TypeNodeBase, Decl(narrowingUnionToUnion4.ts, 18, 1)) + + kind: SyntaxKind.ThisKeyword; +>kind : Symbol(ThisExpression.kind, Decl(narrowingUnionToUnion4.ts, 32, 70)) +>SyntaxKind : Symbol(SyntaxKind, Decl(narrowingUnionToUnion4.ts, 0, 0)) +>ThisKeyword : Symbol(SyntaxKind.ThisKeyword, Decl(narrowingUnionToUnion4.ts, 7, 15)) +} + +interface NewExpression extends PrimaryExpressionBase { +>NewExpression : Symbol(NewExpression, Decl(narrowingUnionToUnion4.ts, 34, 1)) +>PrimaryExpressionBase : Symbol(PrimaryExpressionBase, Decl(narrowingUnionToUnion4.ts, 105, 1)) + + kind: SyntaxKind.NewExpression; +>kind : Symbol(NewExpression.kind, Decl(narrowingUnionToUnion4.ts, 36, 55)) +>SyntaxKind : Symbol(SyntaxKind, Decl(narrowingUnionToUnion4.ts, 0, 0)) +>NewExpression : Symbol(SyntaxKind.NewExpression, Decl(narrowingUnionToUnion4.ts, 13, 26)) + + expression: Expression; +>expression : Symbol(NewExpression.expression, Decl(narrowingUnionToUnion4.ts, 37, 33)) +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion4.ts, 76, 18)) +} + +interface LiteralLikeNodeBase extends BaseNode { +>LiteralLikeNodeBase : Symbol(LiteralLikeNodeBase, Decl(narrowingUnionToUnion4.ts, 39, 1)) +>BaseNode : Symbol(BaseNode, Decl(narrowingUnionToUnion4.ts, 81, 22)) + + text: string; +>text : Symbol(LiteralLikeNodeBase.text, Decl(narrowingUnionToUnion4.ts, 41, 48)) + + isUnterminated?: boolean; +>isUnterminated : Symbol(LiteralLikeNodeBase.isUnterminated, Decl(narrowingUnionToUnion4.ts, 42, 15)) + + hasExtendedUnicodeEscape?: boolean; +>hasExtendedUnicodeEscape : Symbol(LiteralLikeNodeBase.hasExtendedUnicodeEscape, Decl(narrowingUnionToUnion4.ts, 43, 27)) +} + +interface LiteralExpressionBase +>LiteralExpressionBase : Symbol(LiteralExpressionBase, Decl(narrowingUnionToUnion4.ts, 45, 1)) + + extends LiteralLikeNodeBase, +>LiteralLikeNodeBase : Symbol(LiteralLikeNodeBase, Decl(narrowingUnionToUnion4.ts, 39, 1)) + + PrimaryExpressionBase { +>PrimaryExpressionBase : Symbol(PrimaryExpressionBase, Decl(narrowingUnionToUnion4.ts, 105, 1)) + + _literalExpressionBrand: any; +>_literalExpressionBrand : Symbol(LiteralExpressionBase._literalExpressionBrand, Decl(narrowingUnionToUnion4.ts, 49, 27)) +} + +interface StringLiteral extends LiteralExpressionBase { +>StringLiteral : Symbol(StringLiteral, Decl(narrowingUnionToUnion4.ts, 51, 1)) +>LiteralExpressionBase : Symbol(LiteralExpressionBase, Decl(narrowingUnionToUnion4.ts, 45, 1)) + + kind: SyntaxKind.StringLiteral; +>kind : Symbol(StringLiteral.kind, Decl(narrowingUnionToUnion4.ts, 53, 55)) +>SyntaxKind : Symbol(SyntaxKind, Decl(narrowingUnionToUnion4.ts, 0, 0)) +>StringLiteral : Symbol(SyntaxKind.StringLiteral, Decl(narrowingUnionToUnion4.ts, 15, 17)) + + singleQuote?: boolean; +>singleQuote : Symbol(StringLiteral.singleQuote, Decl(narrowingUnionToUnion4.ts, 54, 33)) +} + +interface NumericLiteral extends LiteralExpressionBase { +>NumericLiteral : Symbol(NumericLiteral, Decl(narrowingUnionToUnion4.ts, 56, 1)) +>LiteralExpressionBase : Symbol(LiteralExpressionBase, Decl(narrowingUnionToUnion4.ts, 45, 1)) + + kind: SyntaxKind.NumericLiteral; +>kind : Symbol(NumericLiteral.kind, Decl(narrowingUnionToUnion4.ts, 58, 56)) +>SyntaxKind : Symbol(SyntaxKind, Decl(narrowingUnionToUnion4.ts, 0, 0)) +>NumericLiteral : Symbol(SyntaxKind.NumericLiteral, Decl(narrowingUnionToUnion4.ts, 14, 16)) +} + +type LiteralExpression = StringLiteral | NumericLiteral; +>LiteralExpression : Symbol(LiteralExpression, Decl(narrowingUnionToUnion4.ts, 60, 1)) +>StringLiteral : Symbol(StringLiteral, Decl(narrowingUnionToUnion4.ts, 51, 1)) +>NumericLiteral : Symbol(NumericLiteral, Decl(narrowingUnionToUnion4.ts, 56, 1)) + +interface TemplateExpression extends PrimaryExpressionBase { +>TemplateExpression : Symbol(TemplateExpression, Decl(narrowingUnionToUnion4.ts, 62, 56)) +>PrimaryExpressionBase : Symbol(PrimaryExpressionBase, Decl(narrowingUnionToUnion4.ts, 105, 1)) + + kind: SyntaxKind.TemplateExpression; +>kind : Symbol(TemplateExpression.kind, Decl(narrowingUnionToUnion4.ts, 64, 60)) +>SyntaxKind : Symbol(SyntaxKind, Decl(narrowingUnionToUnion4.ts, 0, 0)) +>TemplateExpression : Symbol(SyntaxKind.TemplateExpression, Decl(narrowingUnionToUnion4.ts, 16, 16)) +} + +type PrimaryExpression = +>PrimaryExpression : Symbol(PrimaryExpression, Decl(narrowingUnionToUnion4.ts, 66, 1)) + + | Identifier +>Identifier : Symbol(Identifier, Decl(narrowingUnionToUnion4.ts, 109, 1)) + + | NullLiteral +>NullLiteral : Symbol(NullLiteral, Decl(narrowingUnionToUnion4.ts, 22, 1)) + + | BooleanLiteral +>BooleanLiteral : Symbol(BooleanLiteral, Decl(narrowingUnionToUnion4.ts, 26, 1)) + + | ThisExpression +>ThisExpression : Symbol(ThisExpression, Decl(narrowingUnionToUnion4.ts, 30, 1)) + + | LiteralExpression +>LiteralExpression : Symbol(LiteralExpression, Decl(narrowingUnionToUnion4.ts, 60, 1)) + + | TemplateExpression +>TemplateExpression : Symbol(TemplateExpression, Decl(narrowingUnionToUnion4.ts, 62, 56)) + + | ParenthesizedExpression +>ParenthesizedExpression : Symbol(ParenthesizedExpression, Decl(narrowingUnionToUnion4.ts, 125, 1)) + + | NewExpression; +>NewExpression : Symbol(NewExpression, Decl(narrowingUnionToUnion4.ts, 34, 1)) + +type Expression = +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion4.ts, 76, 18)) + + | PropertyAccessExpression +>PropertyAccessExpression : Symbol(PropertyAccessExpression, Decl(narrowingUnionToUnion4.ts, 114, 1)) + + | PropertyAccessEntityNameExpression +>PropertyAccessEntityNameExpression : Symbol(PropertyAccessEntityNameExpression, Decl(narrowingUnionToUnion4.ts, 120, 1)) + + | PrimaryExpression; +>PrimaryExpression : Symbol(PrimaryExpression, Decl(narrowingUnionToUnion4.ts, 66, 1)) + +interface BaseNode { +>BaseNode : Symbol(BaseNode, Decl(narrowingUnionToUnion4.ts, 81, 22)) + + kind: SyntaxKind; +>kind : Symbol(BaseNode.kind, Decl(narrowingUnionToUnion4.ts, 83, 20)) +>SyntaxKind : Symbol(SyntaxKind, Decl(narrowingUnionToUnion4.ts, 0, 0)) +} + +interface ExpressionBase extends BaseNode { +>ExpressionBase : Symbol(ExpressionBase, Decl(narrowingUnionToUnion4.ts, 85, 1)) +>BaseNode : Symbol(BaseNode, Decl(narrowingUnionToUnion4.ts, 81, 22)) + + _expressionBrand: any; +>_expressionBrand : Symbol(ExpressionBase._expressionBrand, Decl(narrowingUnionToUnion4.ts, 87, 43)) +} + +interface UnaryExpressionBase extends ExpressionBase { +>UnaryExpressionBase : Symbol(UnaryExpressionBase, Decl(narrowingUnionToUnion4.ts, 89, 1)) +>ExpressionBase : Symbol(ExpressionBase, Decl(narrowingUnionToUnion4.ts, 85, 1)) + + _unaryExpressionBrand: any; +>_unaryExpressionBrand : Symbol(UnaryExpressionBase._unaryExpressionBrand, Decl(narrowingUnionToUnion4.ts, 91, 54)) +} + +interface UpdateExpressionBase extends UnaryExpressionBase { +>UpdateExpressionBase : Symbol(UpdateExpressionBase, Decl(narrowingUnionToUnion4.ts, 93, 1)) +>UnaryExpressionBase : Symbol(UnaryExpressionBase, Decl(narrowingUnionToUnion4.ts, 89, 1)) + + _updateExpressionBrand: any; +>_updateExpressionBrand : Symbol(UpdateExpressionBase._updateExpressionBrand, Decl(narrowingUnionToUnion4.ts, 95, 60)) +} + +interface LeftHandSideExpressionBase extends UpdateExpressionBase { +>LeftHandSideExpressionBase : Symbol(LeftHandSideExpressionBase, Decl(narrowingUnionToUnion4.ts, 97, 1)) +>UpdateExpressionBase : Symbol(UpdateExpressionBase, Decl(narrowingUnionToUnion4.ts, 93, 1)) + + _leftHandSideExpressionBrand: any; +>_leftHandSideExpressionBrand : Symbol(LeftHandSideExpressionBase._leftHandSideExpressionBrand, Decl(narrowingUnionToUnion4.ts, 99, 67)) +} + +interface MemberExpressionBase extends LeftHandSideExpressionBase { +>MemberExpressionBase : Symbol(MemberExpressionBase, Decl(narrowingUnionToUnion4.ts, 101, 1)) +>LeftHandSideExpressionBase : Symbol(LeftHandSideExpressionBase, Decl(narrowingUnionToUnion4.ts, 97, 1)) + + _memberExpressionBrand: any; +>_memberExpressionBrand : Symbol(MemberExpressionBase._memberExpressionBrand, Decl(narrowingUnionToUnion4.ts, 103, 67)) +} + +interface PrimaryExpressionBase extends MemberExpressionBase { +>PrimaryExpressionBase : Symbol(PrimaryExpressionBase, Decl(narrowingUnionToUnion4.ts, 105, 1)) +>MemberExpressionBase : Symbol(MemberExpressionBase, Decl(narrowingUnionToUnion4.ts, 101, 1)) + + _primaryExpressionBrand: any; +>_primaryExpressionBrand : Symbol(PrimaryExpressionBase._primaryExpressionBrand, Decl(narrowingUnionToUnion4.ts, 107, 62)) +} + +interface Identifier extends PrimaryExpressionBase { +>Identifier : Symbol(Identifier, Decl(narrowingUnionToUnion4.ts, 109, 1)) +>PrimaryExpressionBase : Symbol(PrimaryExpressionBase, Decl(narrowingUnionToUnion4.ts, 105, 1)) + + kind: SyntaxKind.Identifier; +>kind : Symbol(Identifier.kind, Decl(narrowingUnionToUnion4.ts, 111, 52)) +>SyntaxKind : Symbol(SyntaxKind, Decl(narrowingUnionToUnion4.ts, 0, 0)) +>Identifier : Symbol(SyntaxKind.Identifier, Decl(narrowingUnionToUnion4.ts, 0, 23)) + + escapedText: string; +>escapedText : Symbol(Identifier.escapedText, Decl(narrowingUnionToUnion4.ts, 112, 30)) +} + +interface PropertyAccessExpression extends MemberExpressionBase { +>PropertyAccessExpression : Symbol(PropertyAccessExpression, Decl(narrowingUnionToUnion4.ts, 114, 1)) +>MemberExpressionBase : Symbol(MemberExpressionBase, Decl(narrowingUnionToUnion4.ts, 101, 1)) + + kind: SyntaxKind.PropertyAccessExpression; +>kind : Symbol(PropertyAccessExpression.kind, Decl(narrowingUnionToUnion4.ts, 116, 65)) +>SyntaxKind : Symbol(SyntaxKind, Decl(narrowingUnionToUnion4.ts, 0, 0)) +>PropertyAccessExpression : Symbol(SyntaxKind.PropertyAccessExpression, Decl(narrowingUnionToUnion4.ts, 1, 13)) + + expression: Expression; +>expression : Symbol(PropertyAccessExpression.expression, Decl(narrowingUnionToUnion4.ts, 117, 44)) +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion4.ts, 76, 18)) + + name: Identifier; +>name : Symbol(PropertyAccessExpression.name, Decl(narrowingUnionToUnion4.ts, 118, 25)) +>Identifier : Symbol(Identifier, Decl(narrowingUnionToUnion4.ts, 109, 1)) +} + +interface PropertyAccessEntityNameExpression extends PropertyAccessExpression { +>PropertyAccessEntityNameExpression : Symbol(PropertyAccessEntityNameExpression, Decl(narrowingUnionToUnion4.ts, 120, 1)) +>PropertyAccessExpression : Symbol(PropertyAccessExpression, Decl(narrowingUnionToUnion4.ts, 114, 1)) + + _propertyAccessExpressionLikeQualifiedNameBrand?: any; +>_propertyAccessExpressionLikeQualifiedNameBrand : Symbol(PropertyAccessEntityNameExpression._propertyAccessExpressionLikeQualifiedNameBrand, Decl(narrowingUnionToUnion4.ts, 122, 79)) + + expression: EntityNameExpression; +>expression : Symbol(PropertyAccessEntityNameExpression.expression, Decl(narrowingUnionToUnion4.ts, 123, 56)) +>EntityNameExpression : Symbol(EntityNameExpression, Decl(narrowingUnionToUnion4.ts, 130, 1)) +} + +interface ParenthesizedExpression extends PrimaryExpressionBase { +>ParenthesizedExpression : Symbol(ParenthesizedExpression, Decl(narrowingUnionToUnion4.ts, 125, 1)) +>PrimaryExpressionBase : Symbol(PrimaryExpressionBase, Decl(narrowingUnionToUnion4.ts, 105, 1)) + + kind: SyntaxKind.ParenthesizedExpression; +>kind : Symbol(ParenthesizedExpression.kind, Decl(narrowingUnionToUnion4.ts, 127, 65)) +>SyntaxKind : Symbol(SyntaxKind, Decl(narrowingUnionToUnion4.ts, 0, 0)) +>ParenthesizedExpression : Symbol(SyntaxKind.ParenthesizedExpression, Decl(narrowingUnionToUnion4.ts, 2, 27)) + + expression: Expression; +>expression : Symbol(ParenthesizedExpression.expression, Decl(narrowingUnionToUnion4.ts, 128, 43)) +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion4.ts, 76, 18)) +} + +type EntityNameExpression = +>EntityNameExpression : Symbol(EntityNameExpression, Decl(narrowingUnionToUnion4.ts, 130, 1)) + + | Identifier +>Identifier : Symbol(Identifier, Decl(narrowingUnionToUnion4.ts, 109, 1)) + + | PropertyAccessEntityNameExpression +>PropertyAccessEntityNameExpression : Symbol(PropertyAccessEntityNameExpression, Decl(narrowingUnionToUnion4.ts, 120, 1)) + + | ParenthesizedExpression; +>ParenthesizedExpression : Symbol(ParenthesizedExpression, Decl(narrowingUnionToUnion4.ts, 125, 1)) + +interface ExpressionWithTypeArguments extends BaseNode { +>ExpressionWithTypeArguments : Symbol(ExpressionWithTypeArguments, Decl(narrowingUnionToUnion4.ts, 135, 28)) +>BaseNode : Symbol(BaseNode, Decl(narrowingUnionToUnion4.ts, 81, 22)) + + kind: SyntaxKind.ExpressionWithTypeArguments; +>kind : Symbol(ExpressionWithTypeArguments.kind, Decl(narrowingUnionToUnion4.ts, 137, 56)) +>SyntaxKind : Symbol(SyntaxKind, Decl(narrowingUnionToUnion4.ts, 0, 0)) +>ExpressionWithTypeArguments : Symbol(SyntaxKind.ExpressionWithTypeArguments, Decl(narrowingUnionToUnion4.ts, 3, 26)) + + expression: Expression; +>expression : Symbol(ExpressionWithTypeArguments.expression, Decl(narrowingUnionToUnion4.ts, 138, 47)) +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion4.ts, 76, 18)) +} + +declare function assert(arg: unknown): asserts arg; +>assert : Symbol(assert, Decl(narrowingUnionToUnion4.ts, 140, 1)) +>arg : Symbol(arg, Decl(narrowingUnionToUnion4.ts, 142, 24)) +>arg : Symbol(arg, Decl(narrowingUnionToUnion4.ts, 142, 24)) + +declare function isEntityNameExpression( +>isEntityNameExpression : Symbol(isEntityNameExpression, Decl(narrowingUnionToUnion4.ts, 142, 51)) + + node: Expression, +>node : Symbol(node, Decl(narrowingUnionToUnion4.ts, 144, 40)) +>Expression : Symbol(Expression, Decl(narrowingUnionToUnion4.ts, 76, 18)) + +): node is EntityNameExpression; +>node : Symbol(node, Decl(narrowingUnionToUnion4.ts, 144, 40)) +>EntityNameExpression : Symbol(EntityNameExpression, Decl(narrowingUnionToUnion4.ts, 130, 1)) + +declare function emitEntityName(entityName: EntityNameExpression): void; +>emitEntityName : Symbol(emitEntityName, Decl(narrowingUnionToUnion4.ts, 146, 32)) +>entityName : Symbol(entityName, Decl(narrowingUnionToUnion4.ts, 148, 32)) +>EntityNameExpression : Symbol(EntityNameExpression, Decl(narrowingUnionToUnion4.ts, 130, 1)) + +export function emitExpressionWithTypeArguments( +>emitExpressionWithTypeArguments : Symbol(emitExpressionWithTypeArguments, Decl(narrowingUnionToUnion4.ts, 148, 72)) + + node: ExpressionWithTypeArguments, +>node : Symbol(node, Decl(narrowingUnionToUnion4.ts, 150, 48)) +>ExpressionWithTypeArguments : Symbol(ExpressionWithTypeArguments, Decl(narrowingUnionToUnion4.ts, 135, 28)) + +) { + if (isEntityNameExpression(node.expression)) { +>isEntityNameExpression : Symbol(isEntityNameExpression, Decl(narrowingUnionToUnion4.ts, 142, 51)) +>node.expression : Symbol(ExpressionWithTypeArguments.expression, Decl(narrowingUnionToUnion4.ts, 138, 47)) +>node : Symbol(node, Decl(narrowingUnionToUnion4.ts, 150, 48)) +>expression : Symbol(ExpressionWithTypeArguments.expression, Decl(narrowingUnionToUnion4.ts, 138, 47)) + + assert( +>assert : Symbol(assert, Decl(narrowingUnionToUnion4.ts, 140, 1)) + + node.expression.kind === SyntaxKind.Identifier || +>node.expression.kind : Symbol(kind, Decl(narrowingUnionToUnion4.ts, 116, 65), Decl(narrowingUnionToUnion4.ts, 111, 52), Decl(narrowingUnionToUnion4.ts, 127, 65)) +>node.expression : Symbol(ExpressionWithTypeArguments.expression, Decl(narrowingUnionToUnion4.ts, 138, 47)) +>node : Symbol(node, Decl(narrowingUnionToUnion4.ts, 150, 48)) +>expression : Symbol(ExpressionWithTypeArguments.expression, Decl(narrowingUnionToUnion4.ts, 138, 47)) +>kind : Symbol(kind, Decl(narrowingUnionToUnion4.ts, 116, 65), Decl(narrowingUnionToUnion4.ts, 111, 52), Decl(narrowingUnionToUnion4.ts, 127, 65)) +>SyntaxKind.Identifier : Symbol(SyntaxKind.Identifier, Decl(narrowingUnionToUnion4.ts, 0, 23)) +>SyntaxKind : Symbol(SyntaxKind, Decl(narrowingUnionToUnion4.ts, 0, 0)) +>Identifier : Symbol(SyntaxKind.Identifier, Decl(narrowingUnionToUnion4.ts, 0, 23)) + + node.expression.kind === SyntaxKind.PropertyAccessExpression, +>node.expression.kind : Symbol(kind, Decl(narrowingUnionToUnion4.ts, 116, 65), Decl(narrowingUnionToUnion4.ts, 127, 65)) +>node.expression : Symbol(ExpressionWithTypeArguments.expression, Decl(narrowingUnionToUnion4.ts, 138, 47)) +>node : Symbol(node, Decl(narrowingUnionToUnion4.ts, 150, 48)) +>expression : Symbol(ExpressionWithTypeArguments.expression, Decl(narrowingUnionToUnion4.ts, 138, 47)) +>kind : Symbol(kind, Decl(narrowingUnionToUnion4.ts, 116, 65), Decl(narrowingUnionToUnion4.ts, 127, 65)) +>SyntaxKind.PropertyAccessExpression : Symbol(SyntaxKind.PropertyAccessExpression, Decl(narrowingUnionToUnion4.ts, 1, 13)) +>SyntaxKind : Symbol(SyntaxKind, Decl(narrowingUnionToUnion4.ts, 0, 0)) +>PropertyAccessExpression : Symbol(SyntaxKind.PropertyAccessExpression, Decl(narrowingUnionToUnion4.ts, 1, 13)) + + ); + emitEntityName(node.expression); +>emitEntityName : Symbol(emitEntityName, Decl(narrowingUnionToUnion4.ts, 146, 32)) +>node.expression : Symbol(ExpressionWithTypeArguments.expression, Decl(narrowingUnionToUnion4.ts, 138, 47)) +>node : Symbol(node, Decl(narrowingUnionToUnion4.ts, 150, 48)) +>expression : Symbol(ExpressionWithTypeArguments.expression, Decl(narrowingUnionToUnion4.ts, 138, 47)) + + // ... + } +} + diff --git a/tests/baselines/reference/narrowingUnionToUnion4.types b/tests/baselines/reference/narrowingUnionToUnion4.types new file mode 100644 index 0000000000000..94c864e7f6dd6 --- /dev/null +++ b/tests/baselines/reference/narrowingUnionToUnion4.types @@ -0,0 +1,406 @@ +//// [tests/cases/compiler/narrowingUnionToUnion4.ts] //// + +=== narrowingUnionToUnion4.ts === +const enum SyntaxKind { +>SyntaxKind : SyntaxKind +> : ^^^^^^^^^^ + + Identifier, +>Identifier : SyntaxKind.Identifier +> : ^^^^^^^^^^^^^^^^^^^^^ + + PropertyAccessExpression, +>PropertyAccessExpression : SyntaxKind.PropertyAccessExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ParenthesizedExpression, +>ParenthesizedExpression : SyntaxKind.ParenthesizedExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ExpressionWithTypeArguments, +>ExpressionWithTypeArguments : SyntaxKind.ExpressionWithTypeArguments +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + NullKeyword, +>NullKeyword : SyntaxKind.NullKeyword +> : ^^^^^^^^^^^^^^^^^^^^^^ + + TrueKeyword, +>TrueKeyword : SyntaxKind.TrueKeyword +> : ^^^^^^^^^^^^^^^^^^^^^^ + + FalseKeyword, +>FalseKeyword : SyntaxKind.FalseKeyword +> : ^^^^^^^^^^^^^^^^^^^^^^^ + + ThisKeyword, +>ThisKeyword : SyntaxKind.ThisKeyword +> : ^^^^^^^^^^^^^^^^^^^^^^ + + DeleteExpression, +>DeleteExpression : SyntaxKind.DeleteExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + TypeOfExpression, +>TypeOfExpression : SyntaxKind.TypeOfExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + VoidExpression, +>VoidExpression : SyntaxKind.VoidExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + + AwaitExpression, +>AwaitExpression : SyntaxKind.AwaitExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^ + + TypeAssertionExpression, +>TypeAssertionExpression : SyntaxKind.TypeAssertionExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + NewExpression, +>NewExpression : SyntaxKind.NewExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^ + + NumericLiteral, +>NumericLiteral : SyntaxKind.NumericLiteral +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + + StringLiteral, +>StringLiteral : SyntaxKind.StringLiteral +> : ^^^^^^^^^^^^^^^^^^^^^^^^ + + TemplateExpression, +>TemplateExpression : SyntaxKind.TemplateExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} + +interface TypeNodeBase extends BaseNode { + _typeNodeBrand: any; +>_typeNodeBrand : any +} + +interface NullLiteral extends PrimaryExpressionBase, TypeNodeBase { + kind: SyntaxKind.NullKeyword; +>kind : SyntaxKind.NullKeyword +> : ^^^^^^^^^^^^^^^^^^^^^^ +>SyntaxKind : any +> : ^^^ +} + +interface BooleanLiteral extends PrimaryExpressionBase, TypeNodeBase { + kind: SyntaxKind.TrueKeyword | SyntaxKind.FalseKeyword; +>kind : SyntaxKind.TrueKeyword | SyntaxKind.FalseKeyword +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>SyntaxKind : any +> : ^^^ +>SyntaxKind : any +> : ^^^ +} + +interface ThisExpression extends PrimaryExpressionBase, TypeNodeBase { + kind: SyntaxKind.ThisKeyword; +>kind : SyntaxKind.ThisKeyword +> : ^^^^^^^^^^^^^^^^^^^^^^ +>SyntaxKind : any +> : ^^^ +} + +interface NewExpression extends PrimaryExpressionBase { + kind: SyntaxKind.NewExpression; +>kind : SyntaxKind.NewExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^ +>SyntaxKind : any +> : ^^^ + + expression: Expression; +>expression : Expression +> : ^^^^^^^^^^ +} + +interface LiteralLikeNodeBase extends BaseNode { + text: string; +>text : string +> : ^^^^^^ + + isUnterminated?: boolean; +>isUnterminated : boolean | undefined +> : ^^^^^^^^^^^^^^^^^^^ + + hasExtendedUnicodeEscape?: boolean; +>hasExtendedUnicodeEscape : boolean | undefined +> : ^^^^^^^^^^^^^^^^^^^ +} + +interface LiteralExpressionBase + extends LiteralLikeNodeBase, + PrimaryExpressionBase { + _literalExpressionBrand: any; +>_literalExpressionBrand : any +} + +interface StringLiteral extends LiteralExpressionBase { + kind: SyntaxKind.StringLiteral; +>kind : SyntaxKind.StringLiteral +> : ^^^^^^^^^^^^^^^^^^^^^^^^ +>SyntaxKind : any +> : ^^^ + + singleQuote?: boolean; +>singleQuote : boolean | undefined +> : ^^^^^^^^^^^^^^^^^^^ +} + +interface NumericLiteral extends LiteralExpressionBase { + kind: SyntaxKind.NumericLiteral; +>kind : SyntaxKind.NumericLiteral +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>SyntaxKind : any +> : ^^^ +} + +type LiteralExpression = StringLiteral | NumericLiteral; +>LiteralExpression : LiteralExpression +> : ^^^^^^^^^^^^^^^^^ + +interface TemplateExpression extends PrimaryExpressionBase { + kind: SyntaxKind.TemplateExpression; +>kind : SyntaxKind.TemplateExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>SyntaxKind : any +> : ^^^ +} + +type PrimaryExpression = +>PrimaryExpression : PrimaryExpression +> : ^^^^^^^^^^^^^^^^^ + + | Identifier + | NullLiteral + | BooleanLiteral + | ThisExpression + | LiteralExpression + | TemplateExpression + | ParenthesizedExpression + | NewExpression; + +type Expression = +>Expression : Expression +> : ^^^^^^^^^^ + + | PropertyAccessExpression + | PropertyAccessEntityNameExpression + | PrimaryExpression; + +interface BaseNode { + kind: SyntaxKind; +>kind : SyntaxKind +> : ^^^^^^^^^^ +} + +interface ExpressionBase extends BaseNode { + _expressionBrand: any; +>_expressionBrand : any +} + +interface UnaryExpressionBase extends ExpressionBase { + _unaryExpressionBrand: any; +>_unaryExpressionBrand : any +} + +interface UpdateExpressionBase extends UnaryExpressionBase { + _updateExpressionBrand: any; +>_updateExpressionBrand : any +} + +interface LeftHandSideExpressionBase extends UpdateExpressionBase { + _leftHandSideExpressionBrand: any; +>_leftHandSideExpressionBrand : any +} + +interface MemberExpressionBase extends LeftHandSideExpressionBase { + _memberExpressionBrand: any; +>_memberExpressionBrand : any +} + +interface PrimaryExpressionBase extends MemberExpressionBase { + _primaryExpressionBrand: any; +>_primaryExpressionBrand : any +} + +interface Identifier extends PrimaryExpressionBase { + kind: SyntaxKind.Identifier; +>kind : SyntaxKind.Identifier +> : ^^^^^^^^^^^^^^^^^^^^^ +>SyntaxKind : any +> : ^^^ + + escapedText: string; +>escapedText : string +> : ^^^^^^ +} + +interface PropertyAccessExpression extends MemberExpressionBase { + kind: SyntaxKind.PropertyAccessExpression; +>kind : SyntaxKind.PropertyAccessExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>SyntaxKind : any +> : ^^^ + + expression: Expression; +>expression : Expression +> : ^^^^^^^^^^ + + name: Identifier; +>name : Identifier +> : ^^^^^^^^^^ +} + +interface PropertyAccessEntityNameExpression extends PropertyAccessExpression { + _propertyAccessExpressionLikeQualifiedNameBrand?: any; +>_propertyAccessExpressionLikeQualifiedNameBrand : any + + expression: EntityNameExpression; +>expression : EntityNameExpression +> : ^^^^^^^^^^^^^^^^^^^^ +} + +interface ParenthesizedExpression extends PrimaryExpressionBase { + kind: SyntaxKind.ParenthesizedExpression; +>kind : SyntaxKind.ParenthesizedExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>SyntaxKind : any +> : ^^^ + + expression: Expression; +>expression : Expression +> : ^^^^^^^^^^ +} + +type EntityNameExpression = +>EntityNameExpression : EntityNameExpression +> : ^^^^^^^^^^^^^^^^^^^^ + + | Identifier + | PropertyAccessEntityNameExpression + | ParenthesizedExpression; + +interface ExpressionWithTypeArguments extends BaseNode { + kind: SyntaxKind.ExpressionWithTypeArguments; +>kind : SyntaxKind.ExpressionWithTypeArguments +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>SyntaxKind : any +> : ^^^ + + expression: Expression; +>expression : Expression +> : ^^^^^^^^^^ +} + +declare function assert(arg: unknown): asserts arg; +>assert : (arg: unknown) => asserts arg +> : ^ ^^ ^^^^^ +>arg : unknown +> : ^^^^^^^ + +declare function isEntityNameExpression( +>isEntityNameExpression : (node: Expression) => node is EntityNameExpression +> : ^ ^^ ^^^^^ + + node: Expression, +>node : Expression +> : ^^^^^^^^^^ + +): node is EntityNameExpression; + +declare function emitEntityName(entityName: EntityNameExpression): void; +>emitEntityName : (entityName: EntityNameExpression) => void +> : ^ ^^ ^^^^^ +>entityName : EntityNameExpression +> : ^^^^^^^^^^^^^^^^^^^^ + +export function emitExpressionWithTypeArguments( +>emitExpressionWithTypeArguments : (node: ExpressionWithTypeArguments) => void +> : ^ ^^ ^^^^^^^^^ + + node: ExpressionWithTypeArguments, +>node : ExpressionWithTypeArguments +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +) { + if (isEntityNameExpression(node.expression)) { +>isEntityNameExpression(node.expression) : boolean +> : ^^^^^^^ +>isEntityNameExpression : (node: Expression) => node is EntityNameExpression +> : ^ ^^ ^^^^^ +>node.expression : Expression +> : ^^^^^^^^^^ +>node : ExpressionWithTypeArguments +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>expression : Expression +> : ^^^^^^^^^^ + + assert( +>assert( node.expression.kind === SyntaxKind.Identifier || node.expression.kind === SyntaxKind.PropertyAccessExpression, ) : void +> : ^^^^ +>assert : (arg: unknown) => asserts arg +> : ^ ^^ ^^^^^ + + node.expression.kind === SyntaxKind.Identifier || +>node.expression.kind === SyntaxKind.Identifier || node.expression.kind === SyntaxKind.PropertyAccessExpression : boolean +> : ^^^^^^^ +>node.expression.kind === SyntaxKind.Identifier : boolean +> : ^^^^^^^ +>node.expression.kind : SyntaxKind.Identifier | SyntaxKind.PropertyAccessExpression | SyntaxKind.ParenthesizedExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node.expression : PropertyAccessEntityNameExpression | Identifier | ParenthesizedExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node : ExpressionWithTypeArguments +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>expression : PropertyAccessEntityNameExpression | Identifier | ParenthesizedExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>kind : SyntaxKind.Identifier | SyntaxKind.PropertyAccessExpression | SyntaxKind.ParenthesizedExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>SyntaxKind.Identifier : SyntaxKind.Identifier +> : ^^^^^^^^^^^^^^^^^^^^^ +>SyntaxKind : typeof SyntaxKind +> : ^^^^^^^^^^^^^^^^^ +>Identifier : SyntaxKind.Identifier +> : ^^^^^^^^^^^^^^^^^^^^^ + + node.expression.kind === SyntaxKind.PropertyAccessExpression, +>node.expression.kind === SyntaxKind.PropertyAccessExpression : boolean +> : ^^^^^^^ +>node.expression.kind : SyntaxKind.PropertyAccessExpression | SyntaxKind.ParenthesizedExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node.expression : PropertyAccessEntityNameExpression | ParenthesizedExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node : ExpressionWithTypeArguments +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>expression : PropertyAccessEntityNameExpression | ParenthesizedExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>kind : SyntaxKind.PropertyAccessExpression | SyntaxKind.ParenthesizedExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>SyntaxKind.PropertyAccessExpression : SyntaxKind.PropertyAccessExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>SyntaxKind : typeof SyntaxKind +> : ^^^^^^^^^^^^^^^^^ +>PropertyAccessExpression : SyntaxKind.PropertyAccessExpression +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ); + emitEntityName(node.expression); +>emitEntityName(node.expression) : void +> : ^^^^ +>emitEntityName : (entityName: EntityNameExpression) => void +> : ^ ^^ ^^^^^ +>node.expression : PropertyAccessEntityNameExpression | Identifier +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>node : ExpressionWithTypeArguments +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>expression : PropertyAccessEntityNameExpression | Identifier +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + // ... + } +} + diff --git a/tests/cases/compiler/narrowingUnionToUnion4.ts b/tests/cases/compiler/narrowingUnionToUnion4.ts new file mode 100644 index 0000000000000..e9fbe977489f4 --- /dev/null +++ b/tests/cases/compiler/narrowingUnionToUnion4.ts @@ -0,0 +1,165 @@ +// @strict: true +// @noEmit: true + +const enum SyntaxKind { + Identifier, + PropertyAccessExpression, + ParenthesizedExpression, + ExpressionWithTypeArguments, + NullKeyword, + TrueKeyword, + FalseKeyword, + ThisKeyword, + DeleteExpression, + TypeOfExpression, + VoidExpression, + AwaitExpression, + TypeAssertionExpression, + NewExpression, + NumericLiteral, + StringLiteral, + TemplateExpression, +} + +interface TypeNodeBase extends BaseNode { + _typeNodeBrand: any; +} + +interface NullLiteral extends PrimaryExpressionBase, TypeNodeBase { + kind: SyntaxKind.NullKeyword; +} + +interface BooleanLiteral extends PrimaryExpressionBase, TypeNodeBase { + kind: SyntaxKind.TrueKeyword | SyntaxKind.FalseKeyword; +} + +interface ThisExpression extends PrimaryExpressionBase, TypeNodeBase { + kind: SyntaxKind.ThisKeyword; +} + +interface NewExpression extends PrimaryExpressionBase { + kind: SyntaxKind.NewExpression; + expression: Expression; +} + +interface LiteralLikeNodeBase extends BaseNode { + text: string; + isUnterminated?: boolean; + hasExtendedUnicodeEscape?: boolean; +} + +interface LiteralExpressionBase + extends LiteralLikeNodeBase, + PrimaryExpressionBase { + _literalExpressionBrand: any; +} + +interface StringLiteral extends LiteralExpressionBase { + kind: SyntaxKind.StringLiteral; + singleQuote?: boolean; +} + +interface NumericLiteral extends LiteralExpressionBase { + kind: SyntaxKind.NumericLiteral; +} + +type LiteralExpression = StringLiteral | NumericLiteral; + +interface TemplateExpression extends PrimaryExpressionBase { + kind: SyntaxKind.TemplateExpression; +} + +type PrimaryExpression = + | Identifier + | NullLiteral + | BooleanLiteral + | ThisExpression + | LiteralExpression + | TemplateExpression + | ParenthesizedExpression + | NewExpression; + +type Expression = + | PropertyAccessExpression + | PropertyAccessEntityNameExpression + | PrimaryExpression; + +interface BaseNode { + kind: SyntaxKind; +} + +interface ExpressionBase extends BaseNode { + _expressionBrand: any; +} + +interface UnaryExpressionBase extends ExpressionBase { + _unaryExpressionBrand: any; +} + +interface UpdateExpressionBase extends UnaryExpressionBase { + _updateExpressionBrand: any; +} + +interface LeftHandSideExpressionBase extends UpdateExpressionBase { + _leftHandSideExpressionBrand: any; +} + +interface MemberExpressionBase extends LeftHandSideExpressionBase { + _memberExpressionBrand: any; +} + +interface PrimaryExpressionBase extends MemberExpressionBase { + _primaryExpressionBrand: any; +} + +interface Identifier extends PrimaryExpressionBase { + kind: SyntaxKind.Identifier; + escapedText: string; +} + +interface PropertyAccessExpression extends MemberExpressionBase { + kind: SyntaxKind.PropertyAccessExpression; + expression: Expression; + name: Identifier; +} + +interface PropertyAccessEntityNameExpression extends PropertyAccessExpression { + _propertyAccessExpressionLikeQualifiedNameBrand?: any; + expression: EntityNameExpression; +} + +interface ParenthesizedExpression extends PrimaryExpressionBase { + kind: SyntaxKind.ParenthesizedExpression; + expression: Expression; +} + +type EntityNameExpression = + | Identifier + | PropertyAccessEntityNameExpression + | ParenthesizedExpression; + +interface ExpressionWithTypeArguments extends BaseNode { + kind: SyntaxKind.ExpressionWithTypeArguments; + expression: Expression; +} + +declare function assert(arg: unknown): asserts arg; + +declare function isEntityNameExpression( + node: Expression, +): node is EntityNameExpression; + +declare function emitEntityName(entityName: EntityNameExpression): void; + +export function emitExpressionWithTypeArguments( + node: ExpressionWithTypeArguments, +) { + if (isEntityNameExpression(node.expression)) { + assert( + node.expression.kind === SyntaxKind.Identifier || + node.expression.kind === SyntaxKind.PropertyAccessExpression, + ); + emitEntityName(node.expression); + // ... + } +} From 29ae00ac0f6b255cf3bfcad3967fed0a4e245e27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 21 Apr 2025 10:07:49 +0200 Subject: [PATCH 9/9] try to optimize --- src/compiler/checker.ts | 98 +++++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 34 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 93aec6dd7800e..c88cbb3212c53 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27842,14 +27842,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const t of types) { const mapped = t.flags & TypeFlags.Union ? mapType(t, mapper, noReductions) : mapper(t); changed ||= t !== mapped; - if (mapped) { - if (!mappedTypes) { - mappedTypes = [mapped]; - } - else { - mappedTypes.push(mapped); - } - } + mappedTypes = append(mappedTypes, mapped); } return changed ? mappedTypes && getUnionType(mappedTypes, noReductions ? UnionReduction.None : UnionReduction.Literal) : type; } @@ -29343,32 +29336,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // constituents that are unrelated to the candidate. const isRelated = checkDerived ? isTypeDerivedFrom : isTypeSubtypeOf; const keyPropertyName = type.flags & TypeFlags.Union ? getKeyPropertyName(type as UnionType) : undefined; - let matchedCandidates: Type[] = []; - let narrowedType = mapType(type, t => - mapType( - candidate, - c => { - if (keyPropertyName) { - // If a discriminant property is available, use only matching constituents to reduce the type. - const discriminant = keyPropertyName && getTypeOfPropertyOfType(c, keyPropertyName); - const keyTypeConstituent = discriminant && getConstituentTypeForKeyType(type as UnionType, discriminant); - if (keyTypeConstituent && keyTypeConstituent !== t) { - return neverType; - } - } - // For each constituent t in the current type, if t and and c are directly related, pick the most - // specific of the two. When t and c are related in both directions, we prefer c for type predicates - // because that is the asserted type, but t for `instanceof` because generics aren't reflected in - // prototype object types. - const directlyRelated = checkDerived ? - (isTypeDerivedFrom(t, c) ? t : isTypeDerivedFrom(c, t) ? c : neverType) : - (isTypeStrictSubtypeOf(t, c) ? t : isTypeStrictSubtypeOf(c, t) ? c : isTypeSubtypeOf(t, c) ? t : isTypeSubtypeOf(c, t) ? c : neverType); - if (!(directlyRelated.flags & TypeFlags.Never)) { - matchedCandidates = appendIfUnique(matchedCandidates, c); - } - return directlyRelated; - }, - )); + const matchedCandidates: Type[] = []; + let narrowedType = mapTypeInContextOfCandidate( + type, + type, + candidate, + (t, c) => { + // For each constituent t in the current type, if t and and c are directly related, pick the most + // specific of the two. When t and c are related in both directions, we prefer c for type predicates + // because that is the asserted type, but t for `instanceof` because generics aren't reflected in + // prototype object types. + const directlyRelated = checkDerived ? + (isTypeDerivedFrom(t, c) ? t : isTypeDerivedFrom(c, t) ? c : neverType) : + (isTypeStrictSubtypeOf(t, c) ? t : isTypeStrictSubtypeOf(c, t) ? c : isTypeSubtypeOf(t, c) ? t : isTypeSubtypeOf(c, t) ? c : neverType); + if (!(directlyRelated.flags & TypeFlags.Never)) { + insertType(matchedCandidates, c); + } + return directlyRelated; + }, + ); if (matchedCandidates.length !== countTypes(candidate)) { // If there are leftover constituents not directly related, create intersections for any generic constituents that // are related by constraint. @@ -29388,6 +29374,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { isTypeAssignableTo(type, candidate) ? type : isTypeAssignableTo(candidate, type) ? candidate : getIntersectionType([type, candidate]); + + function mapTypeInContextOfCandidate(originalType: Type, type: Type, candidate: Type, mapper: (t: Type, c: Type) => Type): Type { + if (type.flags & TypeFlags.Never) { + return type; + } + if (!(type.flags & TypeFlags.Union)) { + return mapType(candidate, c => mapper(type, c)); + } + const origin = (type as UnionType).origin; + const types = origin && origin.flags & TypeFlags.Union ? (origin as UnionType).types : (type as UnionType).types; + if (keyPropertyName) { + let matchedTypes: Type[] | undefined; + let matchingCandidates: Type[] | undefined; + const skipped = forEachType(candidate, c => { + const discriminant = keyPropertyName && getTypeOfPropertyOfType(c, keyPropertyName); + const matching = discriminant && getConstituentTypeForKeyType(originalType as UnionType, discriminant); + if (!matching || containsType(types, matching)) { + matchedTypes = append(matchedTypes, matching); + matchingCandidates = append(matchingCandidates, c); + return; + } + return true; + }); + if (!skipped && matchedTypes) { + const mappedTypes: Type[] = []; + for (const t of matchedTypes) { + for (const c of matchingCandidates!) { + mappedTypes.push(mapper(t, c)); + } + } + return getUnionType(mappedTypes); + } + } + let mappedTypes: Type[] = []; + let changed = false; + for (const t of types) { + const mapped = t.flags & TypeFlags.Union ? mapTypeInContextOfCandidate(originalType, t, candidate, mapper) : mapType(candidate, c => { + return mapper(t, c); + }); + changed ||= t !== mapped; + mappedTypes = append(mappedTypes, mapped); + } + return changed ? getUnionType(mappedTypes) : type; + } } function narrowTypeByCallExpression(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type {