diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3c48319273a..1e6a16aa75f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8466,15 +8466,19 @@ namespace ts { return result; } - function getTopConditionalType(node: Node): ConditionalTypeNode { - let result: ConditionalTypeNode; + function isPossiblyReferencedInConditionalType(tp: TypeParameter, node: Node) { + if (isTypeParameterPossiblyReferenced(tp, node)) { + return true; + } while (node) { if (node.kind === SyntaxKind.ConditionalType) { - result = node; + if (isTypeParameterPossiblyReferenced(tp, (node).extendsType)) { + return true; + } } node = node.parent; } - return result; + return false; } function getTypeFromConditionalTypeNode(node: ConditionalTypeNode): Type { @@ -8483,8 +8487,7 @@ namespace ts { const checkType = getTypeFromTypeNode(node.checkType); const aliasTypeArguments = getAliasTypeArgumentsForTypeNode(node); const allOuterTypeParameters = getOuterTypeParameters(node, /*includeThisTypes*/ true); - const topNode = getTopConditionalType(node); - const outerTypeParameters = aliasTypeArguments ? allOuterTypeParameters : filter(allOuterTypeParameters, tp => isTypeParameterPossiblyReferenced(tp, topNode)); + const outerTypeParameters = aliasTypeArguments ? allOuterTypeParameters : filter(allOuterTypeParameters, tp => isPossiblyReferencedInConditionalType(tp, node)); const root: ConditionalRoot = { node, checkType, diff --git a/tests/baselines/reference/conditionalTypes2.errors.txt b/tests/baselines/reference/conditionalTypes2.errors.txt index 7e12ca8523b..0e7844babc6 100644 --- a/tests/baselines/reference/conditionalTypes2.errors.txt +++ b/tests/baselines/reference/conditionalTypes2.errors.txt @@ -176,4 +176,19 @@ tests/cases/conformance/types/conditional/conditionalTypes2.ts(75,12): error TS2 toString2(value); } } + + // Repro from #23052 + + type A = + T extends object + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: A; } + : T extends V ? T : never; + + type B = + T extends object + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: B; } + : T extends V ? T : never; + + type C = + { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: C; }; \ No newline at end of file diff --git a/tests/baselines/reference/conditionalTypes2.js b/tests/baselines/reference/conditionalTypes2.js index ee2c1fe27fb..7afb39d42bb 100644 --- a/tests/baselines/reference/conditionalTypes2.js +++ b/tests/baselines/reference/conditionalTypes2.js @@ -119,6 +119,21 @@ function foo(value: T) { toString2(value); } } + +// Repro from #23052 + +type A = + T extends object + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: A; } + : T extends V ? T : never; + +type B = + T extends object + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: B; } + : T extends V ? T : never; + +type C = + { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: C; }; //// [conditionalTypes2.js] @@ -254,3 +269,18 @@ interface B1 extends A1 { declare function toString1(value: object | Function): string; declare function toString2(value: Function): string; declare function foo(value: T): void; +declare type A = T extends object ? { + [Q in { + [P in keyof T]: T[P] extends V ? P : P; + }[keyof T]]: A; +} : T extends V ? T : never; +declare type B = T extends object ? { + [Q in { + [P in keyof T]: T[P] extends V ? P : P; + }[keyof T]]: B; +} : T extends V ? T : never; +declare type C = { + [Q in { + [P in keyof T]: T[P] extends V ? P : P; + }[keyof T]]: C; +}; diff --git a/tests/baselines/reference/conditionalTypes2.symbols b/tests/baselines/reference/conditionalTypes2.symbols index ef58dc6229c..00509458253 100644 --- a/tests/baselines/reference/conditionalTypes2.symbols +++ b/tests/baselines/reference/conditionalTypes2.symbols @@ -414,3 +414,85 @@ function foo(value: T) { } } +// Repro from #23052 + +type A = +>A : Symbol(A, Decl(conditionalTypes2.ts, 119, 1)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 123, 7)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 123, 9)) +>E : Symbol(E, Decl(conditionalTypes2.ts, 123, 12)) + + T extends object +>T : Symbol(T, Decl(conditionalTypes2.ts, 123, 7)) + + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: A; } +>Q : Symbol(Q, Decl(conditionalTypes2.ts, 125, 9)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 125, 17)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 123, 7)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 123, 7)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 125, 17)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 123, 9)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 125, 17)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 125, 17)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 123, 7)) +>A : Symbol(A, Decl(conditionalTypes2.ts, 119, 1)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 123, 7)) +>Q : Symbol(Q, Decl(conditionalTypes2.ts, 125, 9)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 123, 9)) +>E : Symbol(E, Decl(conditionalTypes2.ts, 123, 12)) + + : T extends V ? T : never; +>T : Symbol(T, Decl(conditionalTypes2.ts, 123, 7)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 123, 9)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 123, 7)) + +type B = +>B : Symbol(B, Decl(conditionalTypes2.ts, 126, 30)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 128, 7)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 128, 9)) + + T extends object +>T : Symbol(T, Decl(conditionalTypes2.ts, 128, 7)) + + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: B; } +>Q : Symbol(Q, Decl(conditionalTypes2.ts, 130, 9)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 130, 17)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 128, 7)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 128, 7)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 130, 17)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 128, 9)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 130, 17)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 130, 17)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 128, 7)) +>B : Symbol(B, Decl(conditionalTypes2.ts, 126, 30)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 128, 7)) +>Q : Symbol(Q, Decl(conditionalTypes2.ts, 130, 9)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 128, 9)) + + : T extends V ? T : never; +>T : Symbol(T, Decl(conditionalTypes2.ts, 128, 7)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 128, 9)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 128, 7)) + +type C = +>C : Symbol(C, Decl(conditionalTypes2.ts, 131, 30)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 133, 7)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 133, 9)) +>E : Symbol(E, Decl(conditionalTypes2.ts, 133, 12)) + + { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: C; }; +>Q : Symbol(Q, Decl(conditionalTypes2.ts, 134, 5)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 134, 13)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 133, 7)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 133, 7)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 134, 13)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 133, 9)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 134, 13)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 134, 13)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 133, 7)) +>C : Symbol(C, Decl(conditionalTypes2.ts, 131, 30)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 133, 7)) +>Q : Symbol(Q, Decl(conditionalTypes2.ts, 134, 5)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 133, 9)) +>E : Symbol(E, Decl(conditionalTypes2.ts, 133, 12)) + diff --git a/tests/baselines/reference/conditionalTypes2.types b/tests/baselines/reference/conditionalTypes2.types index 249c05f1ad3..5af4de235c8 100644 --- a/tests/baselines/reference/conditionalTypes2.types +++ b/tests/baselines/reference/conditionalTypes2.types @@ -444,3 +444,85 @@ function foo(value: T) { } } +// Repro from #23052 + +type A = +>A : A +>T : T +>V : V +>E : E + + T extends object +>T : T + + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: A; } +>Q : Q +>P : P +>T : T +>T : T +>P : P +>V : V +>P : P +>P : P +>T : T +>A : A +>T : T +>Q : Q +>V : V +>E : E + + : T extends V ? T : never; +>T : T +>V : V +>T : T + +type B = +>B : B +>T : T +>V : V + + T extends object +>T : T + + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: B; } +>Q : Q +>P : P +>T : T +>T : T +>P : P +>V : V +>P : P +>P : P +>T : T +>B : B +>T : T +>Q : Q +>V : V + + : T extends V ? T : never; +>T : T +>V : V +>T : T + +type C = +>C : C +>T : T +>V : V +>E : E + + { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: C; }; +>Q : Q +>P : P +>T : T +>T : T +>P : P +>V : V +>P : P +>P : P +>T : T +>C : C +>T : T +>Q : Q +>V : V +>E : E + diff --git a/tests/cases/conformance/types/conditional/conditionalTypes2.ts b/tests/cases/conformance/types/conditional/conditionalTypes2.ts index c3418cf924d..4002ab6a0a7 100644 --- a/tests/cases/conformance/types/conditional/conditionalTypes2.ts +++ b/tests/cases/conformance/types/conditional/conditionalTypes2.ts @@ -121,3 +121,18 @@ function foo(value: T) { toString2(value); } } + +// Repro from #23052 + +type A = + T extends object + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: A; } + : T extends V ? T : never; + +type B = + T extends object + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: B; } + : T extends V ? T : never; + +type C = + { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: C; };