From 03c1b1843597b1d83f557e98a25ebc86778b430b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 16 Nov 2025 16:37:37 +0100 Subject: [PATCH] Don't create substition types when extending type with infer type parameters --- src/compiler/checker.ts | 2 +- ...aintLeakThroughInferTypeParameter1.symbols | 43 +++++++++++++++++++ ...traintLeakThroughInferTypeParameter1.types | 35 +++++++++++++++ ...onstraintLeakThroughInferTypeParameter1.ts | 20 +++++++++ 4 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.symbols create mode 100644 tests/baselines/reference/distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.types create mode 100644 tests/cases/compiler/distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ba5765c0826a3..274f44725e70e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17200,7 +17200,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Always substitute on type parameters, regardless of variance, since even // in contravariant positions, they may rely on substituted constraints to be valid - if ((covariant || type.flags & TypeFlags.TypeVariable) && parent.kind === SyntaxKind.ConditionalType && node === (parent as ConditionalTypeNode).trueType) { + if ((covariant || type.flags & TypeFlags.TypeVariable) && parent.kind === SyntaxKind.ConditionalType && node === (parent as ConditionalTypeNode).trueType && !getInferTypeParameters(parent as ConditionalTypeNode)) { const constraint = getImpliedConstraint(type, (parent as ConditionalTypeNode).checkType, (parent as ConditionalTypeNode).extendsType); if (constraint) { constraints = append(constraints, constraint); diff --git a/tests/baselines/reference/distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.symbols b/tests/baselines/reference/distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.symbols new file mode 100644 index 0000000000000..9684524da8faf --- /dev/null +++ b/tests/baselines/reference/distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.symbols @@ -0,0 +1,43 @@ +//// [tests/cases/compiler/distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts] //// + +=== distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts === +// https://github.com/microsoft/TypeScript/issues/62761 + +type Value = 1 | 2 +>Value : Symbol(Value, Decl(distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts, 0, 0)) + +type Result = [Value] extends [infer V] +>Result : Symbol(Result, Decl(distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts, 2, 18)) +>Value : Symbol(Value, Decl(distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts, 0, 0)) +>V : Symbol(V, Decl(distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts, 4, 36)) + + ? V extends unknown +>V : Symbol(V, Decl(distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts, 4, 36)) + + ? [V, Value] +>V : Symbol(V, Decl(distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts, 4, 36)) +>Value : Symbol(Value, Decl(distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts, 0, 0)) + + : never + : never + +type Value2 = { prop: 1 | 2 }; +>Value2 : Symbol(Value2, Decl(distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts, 8, 9)) +>prop : Symbol(prop, Decl(distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts, 10, 15)) + +type Result2 = Value2 extends { prop: infer V } +>Result2 : Symbol(Result2, Decl(distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts, 10, 30)) +>Value2 : Symbol(Value2, Decl(distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts, 8, 9)) +>prop : Symbol(prop, Decl(distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts, 12, 31)) +>V : Symbol(V, Decl(distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts, 12, 43)) + + ? V extends unknown +>V : Symbol(V, Decl(distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts, 12, 43)) + + ? [V, Value2] +>V : Symbol(V, Decl(distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts, 12, 43)) +>Value2 : Symbol(Value2, Decl(distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts, 8, 9)) + + : never + : never; + diff --git a/tests/baselines/reference/distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.types b/tests/baselines/reference/distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.types new file mode 100644 index 0000000000000..191129ffecdd4 --- /dev/null +++ b/tests/baselines/reference/distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.types @@ -0,0 +1,35 @@ +//// [tests/cases/compiler/distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts] //// + +=== distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts === +// https://github.com/microsoft/TypeScript/issues/62761 + +type Value = 1 | 2 +>Value : Value +> : ^^^^^ + +type Result = [Value] extends [infer V] +>Result : [1, Value] | [2, Value] +> : ^^^^^^^^^^^^^^^^^^^^^^^ + + ? V extends unknown + ? [V, Value] + : never + : never + +type Value2 = { prop: 1 | 2 }; +>Value2 : Value2 +> : ^^^^^^ +>prop : 1 | 2 +> : ^^^^^ + +type Result2 = Value2 extends { prop: infer V } +>Result2 : [1, Value2] | [2, Value2] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>prop : V +> : ^ + + ? V extends unknown + ? [V, Value2] + : never + : never; + diff --git a/tests/cases/compiler/distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts b/tests/cases/compiler/distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts new file mode 100644 index 0000000000000..51fe44143199a --- /dev/null +++ b/tests/cases/compiler/distributiveConditionalTypeNoConstraintLeakThroughInferTypeParameter1.ts @@ -0,0 +1,20 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/62761 + +type Value = 1 | 2 + +type Result = [Value] extends [infer V] + ? V extends unknown + ? [V, Value] + : never + : never + +type Value2 = { prop: 1 | 2 }; + +type Result2 = Value2 extends { prop: infer V } + ? V extends unknown + ? [V, Value2] + : never + : never;