Only skip any checks for unwrapped tuples in conditionals, rather than all nondistributive conditionals for backcompat (#42447)

This commit is contained in:
Wesley Wigham 2021-01-28 23:36:43 -08:00 committed by GitHub
parent 9dbfaeef2d
commit 2730cb24f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 107 additions and 4 deletions

View file

@ -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

View file

@ -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'.

View file

@ -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

View file

@ -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))

View file

@ -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

View file

@ -257,7 +257,7 @@ type T61<T> = infer A extends infer B ? infer C : infer D; // Error
>T61 : T61<T>
type T62<T> = U extends (infer U)[] ? U : U; // Error
>T62 : unknown
>T62 : any
type T63<T> = T extends (infer A extends infer B ? infer C : infer D) ? string : number;
>T63 : T63<T>

View file

@ -105,7 +105,7 @@ type TT3 = TupleOf<number, any>;
>TT3 : number[]
type TT4 = TupleOf<number, 100>; // Depth error
>TT4 : [any, ...any[]]
>TT4 : any
function f22<N extends number, M extends N>(tn: TupleOf<number, N>, tm: TupleOf<number, M>) {
>f22 : <N extends number, M extends N>(tn: TupleOf<number, N>, tm: TupleOf<number, M>) => void

View file

@ -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