diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4293cd82cb7..606ec5a55d4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14647,6 +14647,7 @@ namespace ts { // types of the form 'A extends B ? X : C extends D ? Y : E extends F ? Z : ...' as a single construct for // purposes of resolution. This means such types aren't subject to the instatiation depth limiter. while (true) { + const isUnwrapped = isTypicalNondistributiveConditional(root); const checkType = instantiateType(unwrapNondistributiveConditionalTuple(root, root.checkType), mapper); const checkTypeInstantiable = isGenericObjectType(checkType) || isGenericIndexType(checkType); const extendsType = instantiateType(unwrapNondistributiveConditionalTuple(root, root.extendsType), mapper); @@ -14672,9 +14673,9 @@ namespace ts { // types with type parameters mapped to the wildcard type, the most permissive instantiations // possible (the wildcard type is assignable to and from all types). If those are not related, // then no instantiations will be and we can just return the false branch type. - if (!(inferredExtendsType.flags & TypeFlags.AnyOrUnknown) && ((checkType.flags & TypeFlags.Any && root.isDistributive) || !isTypeAssignableTo(getPermissiveInstantiation(checkType), getPermissiveInstantiation(inferredExtendsType)))) { + if (!(inferredExtendsType.flags & TypeFlags.AnyOrUnknown) && ((checkType.flags & TypeFlags.Any && !isUnwrapped) || !isTypeAssignableTo(getPermissiveInstantiation(checkType), getPermissiveInstantiation(inferredExtendsType)))) { // Return union of trueType and falseType for 'any' since it matches anything - if (checkType.flags & TypeFlags.Any && root.isDistributive) { + if (checkType.flags & TypeFlags.Any && !isUnwrapped) { (extraTypes || (extraTypes = [])).push(instantiateType(getTypeFromTypeNode(root.node.trueType), combinedMapper || mapper)); } // If falseType is an immediately nested conditional type that isn't distributive or has an diff --git a/tests/baselines/reference/conditionalAnyCheckTypePicksBothBranches.errors.txt b/tests/baselines/reference/conditionalAnyCheckTypePicksBothBranches.errors.txt new file mode 100644 index 00000000000..92722f01a40 --- /dev/null +++ b/tests/baselines/reference/conditionalAnyCheckTypePicksBothBranches.errors.txt @@ -0,0 +1,15 @@ +tests/cases/compiler/conditionalAnyCheckTypePicksBothBranches.ts(9,1): error TS2322: Type '0' is not assignable to type '1'. + + +==== tests/cases/compiler/conditionalAnyCheckTypePicksBothBranches.ts (1 errors) ==== + type T = any extends number ? 1 : 0; + let x: T; + x = 1; + x = 0; // not an error + + type U = [any] extends [number] ? 1 : 0; + let y: U; + y = 1; + y = 0; // error + ~ +!!! error TS2322: Type '0' is not assignable to type '1'. \ No newline at end of file diff --git a/tests/baselines/reference/conditionalAnyCheckTypePicksBothBranches.js b/tests/baselines/reference/conditionalAnyCheckTypePicksBothBranches.js new file mode 100644 index 00000000000..41e72019fd8 --- /dev/null +++ b/tests/baselines/reference/conditionalAnyCheckTypePicksBothBranches.js @@ -0,0 +1,18 @@ +//// [conditionalAnyCheckTypePicksBothBranches.ts] +type T = any extends number ? 1 : 0; +let x: T; +x = 1; +x = 0; // not an error + +type U = [any] extends [number] ? 1 : 0; +let y: U; +y = 1; +y = 0; // error + +//// [conditionalAnyCheckTypePicksBothBranches.js] +var x; +x = 1; +x = 0; // not an error +var y; +y = 1; +y = 0; // error diff --git a/tests/baselines/reference/conditionalAnyCheckTypePicksBothBranches.symbols b/tests/baselines/reference/conditionalAnyCheckTypePicksBothBranches.symbols new file mode 100644 index 00000000000..ca02f89be04 --- /dev/null +++ b/tests/baselines/reference/conditionalAnyCheckTypePicksBothBranches.symbols @@ -0,0 +1,27 @@ +=== tests/cases/compiler/conditionalAnyCheckTypePicksBothBranches.ts === +type T = any extends number ? 1 : 0; +>T : Symbol(T, Decl(conditionalAnyCheckTypePicksBothBranches.ts, 0, 0)) + +let x: T; +>x : Symbol(x, Decl(conditionalAnyCheckTypePicksBothBranches.ts, 1, 3)) +>T : Symbol(T, Decl(conditionalAnyCheckTypePicksBothBranches.ts, 0, 0)) + +x = 1; +>x : Symbol(x, Decl(conditionalAnyCheckTypePicksBothBranches.ts, 1, 3)) + +x = 0; // not an error +>x : Symbol(x, Decl(conditionalAnyCheckTypePicksBothBranches.ts, 1, 3)) + +type U = [any] extends [number] ? 1 : 0; +>U : Symbol(U, Decl(conditionalAnyCheckTypePicksBothBranches.ts, 3, 6)) + +let y: U; +>y : Symbol(y, Decl(conditionalAnyCheckTypePicksBothBranches.ts, 6, 3)) +>U : Symbol(U, Decl(conditionalAnyCheckTypePicksBothBranches.ts, 3, 6)) + +y = 1; +>y : Symbol(y, Decl(conditionalAnyCheckTypePicksBothBranches.ts, 6, 3)) + +y = 0; // error +>y : Symbol(y, Decl(conditionalAnyCheckTypePicksBothBranches.ts, 6, 3)) + diff --git a/tests/baselines/reference/conditionalAnyCheckTypePicksBothBranches.types b/tests/baselines/reference/conditionalAnyCheckTypePicksBothBranches.types new file mode 100644 index 00000000000..f9523f041d0 --- /dev/null +++ b/tests/baselines/reference/conditionalAnyCheckTypePicksBothBranches.types @@ -0,0 +1,33 @@ +=== tests/cases/compiler/conditionalAnyCheckTypePicksBothBranches.ts === +type T = any extends number ? 1 : 0; +>T : 0 | 1 + +let x: T; +>x : 0 | 1 + +x = 1; +>x = 1 : 1 +>x : 0 | 1 +>1 : 1 + +x = 0; // not an error +>x = 0 : 0 +>x : 0 | 1 +>0 : 0 + +type U = [any] extends [number] ? 1 : 0; +>U : 1 + +let y: U; +>y : 1 + +y = 1; +>y = 1 : 1 +>y : 1 +>1 : 1 + +y = 0; // error +>y = 0 : 0 +>y : 1 +>0 : 0 + diff --git a/tests/baselines/reference/inferTypes1.types b/tests/baselines/reference/inferTypes1.types index aa94569cb30..86b0b145fb6 100644 --- a/tests/baselines/reference/inferTypes1.types +++ b/tests/baselines/reference/inferTypes1.types @@ -257,7 +257,7 @@ type T61 = infer A extends infer B ? infer C : infer D; // Error >T61 : T61 type T62 = U extends (infer U)[] ? U : U; // Error ->T62 : unknown +>T62 : any type T63 = T extends (infer A extends infer B ? infer C : infer D) ? string : number; >T63 : T63 diff --git a/tests/baselines/reference/recursiveConditionalTypes.types b/tests/baselines/reference/recursiveConditionalTypes.types index 91ef74f5418..651799b01cf 100644 --- a/tests/baselines/reference/recursiveConditionalTypes.types +++ b/tests/baselines/reference/recursiveConditionalTypes.types @@ -105,7 +105,7 @@ type TT3 = TupleOf; >TT3 : number[] type TT4 = TupleOf; // Depth error ->TT4 : [any, ...any[]] +>TT4 : any function f22(tn: TupleOf, tm: TupleOf) { >f22 : (tn: TupleOf, tm: TupleOf) => void diff --git a/tests/cases/compiler/conditionalAnyCheckTypePicksBothBranches.ts b/tests/cases/compiler/conditionalAnyCheckTypePicksBothBranches.ts new file mode 100644 index 00000000000..46ecd232fa9 --- /dev/null +++ b/tests/cases/compiler/conditionalAnyCheckTypePicksBothBranches.ts @@ -0,0 +1,9 @@ +type T = any extends number ? 1 : 0; +let x: T; +x = 1; +x = 0; // not an error + +type U = [any] extends [number] ? 1 : 0; +let y: U; +y = 1; +y = 0; // error \ No newline at end of file