Skip to content

Commit b554a2f

Browse files
committed
Allow nested conditionals to be related via constraints
1 parent dfc0b58 commit b554a2f

9 files changed

+486
-210
lines changed

src/compiler/checker.ts

+10-6
Original file line numberDiff line numberDiff line change
@@ -15974,19 +15974,23 @@ namespace ts {
1597415974
}
1597515975
}
1597615976
else {
15977+
// conditionals aren't related to one another via distributive constraint as it is much too inaccurate and allows way
15978+
// more assignments than are desirable (since it maps the source check type to its constraint, it loses information)
1597715979
const distributiveConstraint = getConstraintOfDistributiveConditionalType(<ConditionalType>source);
1597815980
if (distributiveConstraint) {
1597915981
if (result = isRelatedTo(distributiveConstraint, target, reportErrors)) {
1598015982
resetErrorInfo(saveErrorInfo);
1598115983
return result;
1598215984
}
1598315985
}
15984-
const defaultConstraint = getDefaultConstraintOfConditionalType(<ConditionalType>source);
15985-
if (defaultConstraint) {
15986-
if (result = isRelatedTo(defaultConstraint, target, reportErrors)) {
15987-
resetErrorInfo(saveErrorInfo);
15988-
return result;
15989-
}
15986+
}
15987+
// while conditionals _can_ be related to one another via normal constraint, as, eg, `A extends B ? O : never` should be assignable to `O`
15988+
// when `O` is a conditional (`never` is trivially aissgnable to `O`, as is `O`!).
15989+
const defaultConstraint = getDefaultConstraintOfConditionalType(<ConditionalType>source);
15990+
if (defaultConstraint) {
15991+
if (result = isRelatedTo(defaultConstraint, target, reportErrors)) {
15992+
resetErrorInfo(saveErrorInfo);
15993+
return result;
1599015994
}
1599115995
}
1599215996
}

tests/baselines/reference/circularlyConstrainedMappedTypeContainingConditionalNoInfiniteInstantiationDepth.errors.txt

+110-86
Large diffs are not rendered by default.

tests/baselines/reference/conditionalTypes1.errors.txt

+18-10
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.
@@ -51,7 +53,9 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(160,5): error TS2
5153
Type 'string' is not assignable to type 'ZeroOf<T>'.
5254
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>'.
5355
tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS2322: Type 'T95<U>' is not assignable to type 'T94<U>'.
54-
Type 'boolean' is not assignable to type 'true'.
56+
Type 'number | boolean' is not assignable to type 'T94<U>'.
57+
Type 'number' is not assignable to type 'T94<U>'.
58+
Type 'boolean' is not assignable to type 'true'.
5559

5660

5761
==== tests/cases/conformance/types/conditional/conditionalTypes1.ts (22 errors) ====
@@ -209,9 +213,10 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS
209213
y = z; // Error
210214
~
211215
!!! error TS2322: Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
212-
!!! error TS2322: Type 'keyof T' is not assignable to type 'never'.
213-
!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'never'.
214-
!!! error TS2322: Type 'string' is not assignable to type 'never'.
216+
!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
217+
!!! error TS2322: Type 'keyof T' is not assignable to type 'never'.
218+
!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'never'.
219+
!!! error TS2322: Type 'string' is not assignable to type 'never'.
215220
z = x; // Error
216221
~
217222
!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'.
@@ -220,7 +225,8 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS
220225
z = y; // Error
221226
~
222227
!!! error TS2322: Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'.
223-
!!! error TS2322: Type 'keyof T' is not assignable to type 'never'.
228+
!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'.
229+
!!! error TS2322: Type 'keyof T' is not assignable to type 'never'.
224230
}
225231

226232
type DeepReadonly<T> =
@@ -419,7 +425,9 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS
419425
const f45 = <U>(value: T95<U>): T94<U> => value; // Error
420426
~~~~~
421427
!!! error TS2322: Type 'T95<U>' is not assignable to type 'T94<U>'.
422-
!!! error TS2322: Type 'boolean' is not assignable to type 'true'.
428+
!!! error TS2322: Type 'number | boolean' is not assignable to type 'T94<U>'.
429+
!!! error TS2322: Type 'number' is not assignable to type 'T94<U>'.
430+
!!! error TS2322: Type 'boolean' is not assignable to type 'true'.
423431

424432
// Repro from #21863
425433

tests/baselines/reference/conditionalTypes2.errors.txt

+32-22
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 '"valueOf"'.
18-
Type 'string | number | symbol' is not assignable to type '"valueOf"'.
19-
Type 'string' is not assignable to type '"valueOf"'.
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 '"valueOf"'.
21+
Type 'string | number | symbol' is not assignable to type '"valueOf"'.
22+
Type 'string' is not assignable to type '"valueOf"'.
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-
'A' is assignable to the constraint of type 'B', but 'B' could be instantiated with a different subtype of constraint '{}'.
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+
'A' is assignable to the constraint of type 'B', but 'B' could be instantiated with a different subtype of constraint '{}'.
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 '"valueOf"'.
81-
!!! error TS2322: Type 'string | number | symbol' is not assignable to type '"valueOf"'.
82-
!!! error TS2322: Type 'string' is not assignable to type '"valueOf"'.
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 '"valueOf"'.
89+
!!! error TS2322: Type 'string | number | symbol' is not assignable to type '"valueOf"'.
90+
!!! error TS2322: Type 'string' is not assignable to type '"valueOf"'.
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: 'A' is assignable to the constraint of type 'B', but 'B' could be instantiated with a different subtype of constraint '{}'.
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: 'A' is assignable to the constraint of type 'B', but 'B' could be instantiated with a different subtype of constraint '{}'.
90100
}
91101

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

0 commit comments

Comments
 (0)