Skip to content

Commit f0216e3

Browse files
authored
Improve reduction of similar intersections in type inference (#51405)
* Change criteria for reducing intersections in type inference * Add regression test
1 parent f1d62f4 commit f0216e3

File tree

5 files changed

+51
-6
lines changed

5 files changed

+51
-6
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22728,14 +22728,11 @@ namespace ts {
2272822728
}
2272922729
source = getUnionType(sources);
2273022730
}
22731-
else if (target.flags & TypeFlags.Intersection && some((target as IntersectionType).types,
22732-
t => !!getInferenceInfoForType(t) || (isGenericMappedType(t) && !!getInferenceInfoForType(getHomomorphicTypeVariable(t) || neverType)))) {
22733-
// We reduce intersection types only when they contain naked type parameters. For example, when
22734-
// inferring from 'string[] & { extra: any }' to 'string[] & T' we want to remove string[] and
22731+
else if (target.flags & TypeFlags.Intersection && !every((target as IntersectionType).types, isNonGenericObjectType)) {
22732+
// We reduce intersection types unless they're simple combinations of object types. For example,
22733+
// when inferring from 'string[] & { extra: any }' to 'string[] & T' we want to remove string[] and
2273522734
// infer { extra: any } for T. But when inferring to 'string[] & Iterable<T>' we want to keep the
2273622735
// string[] on the source side and infer string for T.
22737-
// Likewise, we consider a homomorphic mapped type constrainted to the target type parameter as similar to a "naked type variable"
22738-
// in such scenarios.
2273922736
if (!(source.flags & TypeFlags.Union)) {
2274022737
// Infer between identically matching source and target constituents and remove the matching types.
2274122738
const [sources, targets] = inferFromMatchingTypes(source.flags & TypeFlags.Intersection ? (source as IntersectionType).types : [source], (target as IntersectionType).types, isTypeIdenticalTo);

tests/baselines/reference/unionAndIntersectionInference3.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ declare function foo<T, U>(obj: T & AB<U>): [T, U];
8686
declare let ab: AB<string>;
8787

8888
let z = foo(ab); // [AB<string>, string]
89+
90+
// Repro from #51399
91+
92+
declare let a: <T>() => (T extends true ? true : false) & boolean;
93+
declare let b: <T>() => (T extends true ? true : false) & boolean;
94+
a = b;
8995

9096

9197
//// [unionAndIntersectionInference3.js]
@@ -105,4 +111,5 @@ let x2 = foo2(sa); // unknown
105111
let y2 = foo2(sx); // { extra: number }
106112
withRouter(MyComponent);
107113
let z = foo(ab); // [AB<string>, string]
114+
a = b;
108115
export {};

tests/baselines/reference/unionAndIntersectionInference3.symbols

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,3 +309,19 @@ let z = foo(ab); // [AB<string>, string]
309309
>foo : Symbol(foo, Decl(unionAndIntersectionInference3.ts, 80, 33))
310310
>ab : Symbol(ab, Decl(unionAndIntersectionInference3.ts, 84, 11))
311311

312+
// Repro from #51399
313+
314+
declare let a: <T>() => (T extends true ? true : false) & boolean;
315+
>a : Symbol(a, Decl(unionAndIntersectionInference3.ts, 90, 11))
316+
>T : Symbol(T, Decl(unionAndIntersectionInference3.ts, 90, 16))
317+
>T : Symbol(T, Decl(unionAndIntersectionInference3.ts, 90, 16))
318+
319+
declare let b: <T>() => (T extends true ? true : false) & boolean;
320+
>b : Symbol(b, Decl(unionAndIntersectionInference3.ts, 91, 11))
321+
>T : Symbol(T, Decl(unionAndIntersectionInference3.ts, 91, 16))
322+
>T : Symbol(T, Decl(unionAndIntersectionInference3.ts, 91, 16))
323+
324+
a = b;
325+
>a : Symbol(a, Decl(unionAndIntersectionInference3.ts, 90, 11))
326+
>b : Symbol(b, Decl(unionAndIntersectionInference3.ts, 91, 11))
327+

tests/baselines/reference/unionAndIntersectionInference3.types

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,3 +199,22 @@ let z = foo(ab); // [AB<string>, string]
199199
>foo : <T, U>(obj: T & AB<U>) => [T, U]
200200
>ab : AB<string>
201201

202+
// Repro from #51399
203+
204+
declare let a: <T>() => (T extends true ? true : false) & boolean;
205+
>a : <T>() => (T extends true ? true : false) & boolean
206+
>true : true
207+
>true : true
208+
>false : false
209+
210+
declare let b: <T>() => (T extends true ? true : false) & boolean;
211+
>b : <T>() => (T extends true ? true : false) & boolean
212+
>true : true
213+
>true : true
214+
>false : false
215+
216+
a = b;
217+
>a = b : <T>() => (T extends true ? true : false) & boolean
218+
>a : <T>() => (T extends true ? true : false) & boolean
219+
>b : <T>() => (T extends true ? true : false) & boolean
220+

tests/cases/conformance/types/typeRelationships/typeInference/unionAndIntersectionInference3.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,9 @@ declare function foo<T, U>(obj: T & AB<U>): [T, U];
8888
declare let ab: AB<string>;
8989

9090
let z = foo(ab); // [AB<string>, string]
91+
92+
// Repro from #51399
93+
94+
declare let a: <T>() => (T extends true ? true : false) & boolean;
95+
declare let b: <T>() => (T extends true ? true : false) & boolean;
96+
a = b;

0 commit comments

Comments
 (0)