Skip to content

Commit c513a4a

Browse files
authored
Allow nested conditionals to be related via constraints (#37208)
* Allow nested conditionals to be related via constraints * Delete word in comment
1 parent a83ce33 commit c513a4a

9 files changed

+486
-210
lines changed

src/compiler/checker.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16040,19 +16040,23 @@ namespace ts {
1604016040
}
1604116041
}
1604216042
else {
16043+
// conditionals aren't related to one another via distributive constraint as it is much too inaccurate and allows way
16044+
// more assignments than are desirable (since it maps the source check type to its constraint, it loses information)
1604316045
const distributiveConstraint = getConstraintOfDistributiveConditionalType(<ConditionalType>source);
1604416046
if (distributiveConstraint) {
1604516047
if (result = isRelatedTo(distributiveConstraint, target, reportErrors)) {
1604616048
resetErrorInfo(saveErrorInfo);
1604716049
return result;
1604816050
}
1604916051
}
16050-
const defaultConstraint = getDefaultConstraintOfConditionalType(<ConditionalType>source);
16051-
if (defaultConstraint) {
16052-
if (result = isRelatedTo(defaultConstraint, target, reportErrors)) {
16053-
resetErrorInfo(saveErrorInfo);
16054-
return result;
16055-
}
16052+
}
16053+
// conditionals _can_ be related to one another via normal constraint, as, eg, `A extends B ? O : never` should be assignable to `O`
16054+
// when `O` is a conditional (`never` is trivially aissgnable to `O`, as is `O`!).
16055+
const defaultConstraint = getDefaultConstraintOfConditionalType(<ConditionalType>source);
16056+
if (defaultConstraint) {
16057+
if (result = isRelatedTo(defaultConstraint, target, reportErrors)) {
16058+
resetErrorInfo(saveErrorInfo);
16059+
return result;
1605616060
}
1605716061
}
1605816062
}

tests/baselines/reference/circularlyConstrainedMappedTypeContainingConditionalNoInfiniteInstantiationDepth.errors.txt

Lines changed: 110 additions & 86 deletions
Large diffs are not rendered by default.

tests/baselines/reference/conditionalTypes1.errors.txt

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,16 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(114,5): error TS2
2525
Type 'string | number | symbol' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
2626
Type 'string' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
2727
tests/cases/conformance/types/conditional/conditionalTypes1.ts(115,5): error TS2322: Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
28-
Type 'keyof T' is not assignable to type 'never'.
29-
Type 'string | number | symbol' is not assignable to type 'never'.
30-
Type 'string' is not assignable to type 'never'.
28+
Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
29+
Type 'keyof T' is not assignable to type 'never'.
30+
Type 'string | number | symbol' is not assignable to type 'never'.
31+
Type 'string' is not assignable to type 'never'.
3132
tests/cases/conformance/types/conditional/conditionalTypes1.ts(116,5): error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'.
3233
Type 'string | number | symbol' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'.
3334
Type 'string' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'.
3435
tests/cases/conformance/types/conditional/conditionalTypes1.ts(117,5): error TS2322: Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'.
35-
Type 'keyof T' is not assignable to type 'never'.
36+
Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'.
37+
Type 'keyof T' is not assignable to type 'never'.
3638
tests/cases/conformance/types/conditional/conditionalTypes1.ts(134,10): error TS2540: Cannot assign to 'id' because it is a read-only property.
3739
tests/cases/conformance/types/conditional/conditionalTypes1.ts(135,5): error TS2542: Index signature in type 'DeepReadonlyArray<Part>' only permits reading.
3840
tests/cases/conformance/types/conditional/conditionalTypes1.ts(136,22): error TS2540: Cannot assign to 'id' because it is a read-only property.
@@ -52,7 +54,9 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(160,5): error TS2
5254
Type 'string' is not assignable to type 'ZeroOf<T>'.
5355
tests/cases/conformance/types/conditional/conditionalTypes1.ts(263,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'z' must be of type 'T1', but here has type 'Foo<T & U>'.
5456
tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS2322: Type 'T95<U>' is not assignable to type 'T94<U>'.
55-
Type 'boolean' is not assignable to type 'true'.
57+
Type 'number | boolean' is not assignable to type 'T94<U>'.
58+
Type 'number' is not assignable to type 'T94<U>'.
59+
Type 'boolean' is not assignable to type 'true'.
5660

5761

5862
==== tests/cases/conformance/types/conditional/conditionalTypes1.ts (22 errors) ====
@@ -210,9 +214,10 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS
210214
y = z; // Error
211215
~
212216
!!! error TS2322: Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
213-
!!! error TS2322: Type 'keyof T' is not assignable to type 'never'.
214-
!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'never'.
215-
!!! error TS2322: Type 'string' is not assignable to type 'never'.
217+
!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
218+
!!! error TS2322: Type 'keyof T' is not assignable to type 'never'.
219+
!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'never'.
220+
!!! error TS2322: Type 'string' is not assignable to type 'never'.
216221
z = x; // Error
217222
~
218223
!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'.
@@ -221,7 +226,8 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS
221226
z = y; // Error
222227
~
223228
!!! error TS2322: Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'.
224-
!!! error TS2322: Type 'keyof T' is not assignable to type 'never'.
229+
!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'.
230+
!!! error TS2322: Type 'keyof T' is not assignable to type 'never'.
225231
}
226232

227233
type DeepReadonly<T> =
@@ -421,7 +427,9 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS
421427
const f45 = <U>(value: T95<U>): T94<U> => value; // Error
422428
~~~~~
423429
!!! error TS2322: Type 'T95<U>' is not assignable to type 'T94<U>'.
424-
!!! error TS2322: Type 'boolean' is not assignable to type 'true'.
430+
!!! error TS2322: Type 'number | boolean' is not assignable to type 'T94<U>'.
431+
!!! error TS2322: Type 'number' is not assignable to type 'T94<U>'.
432+
!!! error TS2322: Type 'boolean' is not assignable to type 'true'.
425433

426434
// Repro from #21863
427435

tests/baselines/reference/conditionalTypes2.errors.txt

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,26 @@ tests/cases/conformance/types/conditional/conditionalTypes2.ts(19,5): error TS23
77
tests/cases/conformance/types/conditional/conditionalTypes2.ts(24,5): error TS2322: Type 'Invariant<B>' is not assignable to type 'Invariant<A>'.
88
Types of property 'foo' are incompatible.
99
Type 'B extends string ? keyof B : B' is not assignable to type 'A extends string ? keyof A : A'.
10-
Type 'keyof B' is not assignable to type 'keyof A'.
11-
Type 'string | number | symbol' is not assignable to type 'keyof A'.
12-
Type 'string' is not assignable to type 'keyof A'.
13-
Type 'string' is not assignable to type 'number | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf"'.
14-
Type 'keyof B' is not assignable to type 'number | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf"'.
15-
Type 'string | number | symbol' is not assignable to type 'number | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf"'.
10+
Type 'B | keyof B' is not assignable to type 'A extends string ? keyof A : A'.
11+
Type 'B' is not assignable to type 'A extends string ? keyof A : A'.
12+
Type 'A' is not assignable to type 'A extends string ? keyof A : A'.
13+
Type 'keyof B' is not assignable to type 'keyof A'.
14+
Type 'string | number | symbol' is not assignable to type 'keyof A'.
15+
Type 'string' is not assignable to type 'keyof A'.
1616
Type 'string' is not assignable to type 'number | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf"'.
17-
Type 'keyof B' is not assignable to type 'number'.
18-
Type 'string | number | symbol' is not assignable to type 'number'.
19-
Type 'string' is not assignable to type 'number'.
17+
Type 'keyof B' is not assignable to type 'number | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf"'.
18+
Type 'string | number | symbol' is not assignable to type 'number | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf"'.
19+
Type 'string' is not assignable to type 'number | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf"'.
20+
Type 'keyof B' is not assignable to type 'number'.
21+
Type 'string | number | symbol' is not assignable to type 'number'.
22+
Type 'string' is not assignable to type 'number'.
2023
tests/cases/conformance/types/conditional/conditionalTypes2.ts(25,5): error TS2322: Type 'Invariant<A>' is not assignable to type 'Invariant<B>'.
2124
Types of property 'foo' are incompatible.
2225
Type 'A extends string ? keyof A : A' is not assignable to type 'B extends string ? keyof B : B'.
23-
Type 'A' is not assignable to type 'B'.
24-
'B' could be instantiated with an arbitrary type which could be unrelated to 'A'.
26+
Type 'A | keyof A' is not assignable to type 'B extends string ? keyof B : B'.
27+
Type 'A' is not assignable to type 'B extends string ? keyof B : B'.
28+
Type 'A' is not assignable to type 'B'.
29+
'B' could be instantiated with an arbitrary type which could be unrelated to 'A'.
2530
tests/cases/conformance/types/conditional/conditionalTypes2.ts(73,12): error TS2345: Argument of type 'Extract<Extract<T, Foo>, Bar>' is not assignable to parameter of type '{ foo: string; bat: string; }'.
2631
Property 'bat' is missing in type 'Bar & Foo' but required in type '{ foo: string; bat: string; }'.
2732
Type 'Extract<T, Bar>' is not assignable to type '{ foo: string; bat: string; }'.
@@ -70,23 +75,28 @@ tests/cases/conformance/types/conditional/conditionalTypes2.ts(75,12): error TS2
7075
!!! error TS2322: Type 'Invariant<B>' is not assignable to type 'Invariant<A>'.
7176
!!! error TS2322: Types of property 'foo' are incompatible.
7277
!!! error TS2322: Type 'B extends string ? keyof B : B' is not assignable to type 'A extends string ? keyof A : A'.
73-
!!! error TS2322: Type 'keyof B' is not assignable to type 'keyof A'.
74-
!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'keyof A'.
75-
!!! error TS2322: Type 'string' is not assignable to type 'keyof A'.
76-
!!! error TS2322: Type 'string' is not assignable to type 'number | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf"'.
77-
!!! error TS2322: Type 'keyof B' is not assignable to type 'number | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf"'.
78-
!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'number | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf"'.
78+
!!! error TS2322: Type 'B | keyof B' is not assignable to type 'A extends string ? keyof A : A'.
79+
!!! error TS2322: Type 'B' is not assignable to type 'A extends string ? keyof A : A'.
80+
!!! error TS2322: Type 'A' is not assignable to type 'A extends string ? keyof A : A'.
81+
!!! error TS2322: Type 'keyof B' is not assignable to type 'keyof A'.
82+
!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'keyof A'.
83+
!!! error TS2322: Type 'string' is not assignable to type 'keyof A'.
7984
!!! error TS2322: Type 'string' is not assignable to type 'number | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf"'.
80-
!!! error TS2322: Type 'keyof B' is not assignable to type 'number'.
81-
!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'number'.
82-
!!! error TS2322: Type 'string' is not assignable to type 'number'.
85+
!!! error TS2322: Type 'keyof B' is not assignable to type 'number | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf"'.
86+
!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'number | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf"'.
87+
!!! error TS2322: Type 'string' is not assignable to type 'number | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf"'.
88+
!!! error TS2322: Type 'keyof B' is not assignable to type 'number'.
89+
!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'number'.
90+
!!! error TS2322: Type 'string' is not assignable to type 'number'.
8391
b = a; // Error
8492
~
8593
!!! error TS2322: Type 'Invariant<A>' is not assignable to type 'Invariant<B>'.
8694
!!! error TS2322: Types of property 'foo' are incompatible.
8795
!!! error TS2322: Type 'A extends string ? keyof A : A' is not assignable to type 'B extends string ? keyof B : B'.
88-
!!! error TS2322: Type 'A' is not assignable to type 'B'.
89-
!!! error TS2322: 'B' could be instantiated with an arbitrary type which could be unrelated to 'A'.
96+
!!! error TS2322: Type 'A | keyof A' is not assignable to type 'B extends string ? keyof B : B'.
97+
!!! error TS2322: Type 'A' is not assignable to type 'B extends string ? keyof B : B'.
98+
!!! error TS2322: Type 'A' is not assignable to type 'B'.
99+
!!! error TS2322: 'B' could be instantiated with an arbitrary type which could be unrelated to 'A'.
90100
}
91101

92102
// Extract<T, Function> is a T that is known to be a Function

0 commit comments

Comments
 (0)