Skip to content

Commit d65a3e1

Browse files
authored
Merge pull request #18363 from Microsoft/fixIntersectionInference
Fix intersection inference
2 parents 1b49c8f + 9871c04 commit d65a3e1

File tree

7 files changed

+162
-6
lines changed

7 files changed

+162
-6
lines changed

src/compiler/checker.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -10579,7 +10579,7 @@ namespace ts {
1057910579
priority = savePriority;
1058010580
}
1058110581
}
10582-
else if (source.flags & TypeFlags.UnionOrIntersection) {
10582+
else if (source.flags & TypeFlags.Union) {
1058310583
// Source is a union or intersection type, infer from each constituent type
1058410584
const sourceTypes = (<UnionOrIntersectionType>source).types;
1058510585
for (const sourceType of sourceTypes) {
@@ -10588,7 +10588,7 @@ namespace ts {
1058810588
}
1058910589
else {
1059010590
source = getApparentType(source);
10591-
if (source.flags & TypeFlags.Object) {
10591+
if (source.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
1059210592
const key = source.id + "," + target.id;
1059310593
if (visited && visited.get(key)) {
1059410594
return;
@@ -10668,7 +10668,7 @@ namespace ts {
1066810668
function inferFromProperties(source: Type, target: Type) {
1066910669
const properties = getPropertiesOfObjectType(target);
1067010670
for (const targetProp of properties) {
10671-
const sourceProp = getPropertyOfObjectType(source, targetProp.escapedName);
10671+
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
1067210672
if (sourceProp) {
1067310673
inferFromTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp));
1067410674
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//// [intersectionTypeInference2.ts]
2+
declare function f<T>(x: { prop: T }): T;
3+
4+
declare const a: { prop: string } & { prop: number };
5+
declare const b: { prop: string & number };
6+
7+
f(a); // string & number
8+
f(b); // string & number
9+
10+
// Repro from #18354
11+
12+
declare function f2<T, Key extends keyof T>(obj: {[K in keyof T]: T[K]}, key: Key): T[Key];
13+
14+
declare const obj: { a: string } & { b: string };
15+
f2(obj, 'a');
16+
f2(obj, 'b');
17+
18+
19+
//// [intersectionTypeInference2.js]
20+
f(a); // string & number
21+
f(b); // string & number
22+
f2(obj, 'a');
23+
f2(obj, 'b');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
=== tests/cases/conformance/types/intersection/intersectionTypeInference2.ts ===
2+
declare function f<T>(x: { prop: T }): T;
3+
>f : Symbol(f, Decl(intersectionTypeInference2.ts, 0, 0))
4+
>T : Symbol(T, Decl(intersectionTypeInference2.ts, 0, 19))
5+
>x : Symbol(x, Decl(intersectionTypeInference2.ts, 0, 22))
6+
>prop : Symbol(prop, Decl(intersectionTypeInference2.ts, 0, 26))
7+
>T : Symbol(T, Decl(intersectionTypeInference2.ts, 0, 19))
8+
>T : Symbol(T, Decl(intersectionTypeInference2.ts, 0, 19))
9+
10+
declare const a: { prop: string } & { prop: number };
11+
>a : Symbol(a, Decl(intersectionTypeInference2.ts, 2, 13))
12+
>prop : Symbol(prop, Decl(intersectionTypeInference2.ts, 2, 18))
13+
>prop : Symbol(prop, Decl(intersectionTypeInference2.ts, 2, 37))
14+
15+
declare const b: { prop: string & number };
16+
>b : Symbol(b, Decl(intersectionTypeInference2.ts, 3, 13))
17+
>prop : Symbol(prop, Decl(intersectionTypeInference2.ts, 3, 18))
18+
19+
f(a); // string & number
20+
>f : Symbol(f, Decl(intersectionTypeInference2.ts, 0, 0))
21+
>a : Symbol(a, Decl(intersectionTypeInference2.ts, 2, 13))
22+
23+
f(b); // string & number
24+
>f : Symbol(f, Decl(intersectionTypeInference2.ts, 0, 0))
25+
>b : Symbol(b, Decl(intersectionTypeInference2.ts, 3, 13))
26+
27+
// Repro from #18354
28+
29+
declare function f2<T, Key extends keyof T>(obj: {[K in keyof T]: T[K]}, key: Key): T[Key];
30+
>f2 : Symbol(f2, Decl(intersectionTypeInference2.ts, 6, 5))
31+
>T : Symbol(T, Decl(intersectionTypeInference2.ts, 10, 20))
32+
>Key : Symbol(Key, Decl(intersectionTypeInference2.ts, 10, 22))
33+
>T : Symbol(T, Decl(intersectionTypeInference2.ts, 10, 20))
34+
>obj : Symbol(obj, Decl(intersectionTypeInference2.ts, 10, 44))
35+
>K : Symbol(K, Decl(intersectionTypeInference2.ts, 10, 51))
36+
>T : Symbol(T, Decl(intersectionTypeInference2.ts, 10, 20))
37+
>T : Symbol(T, Decl(intersectionTypeInference2.ts, 10, 20))
38+
>K : Symbol(K, Decl(intersectionTypeInference2.ts, 10, 51))
39+
>key : Symbol(key, Decl(intersectionTypeInference2.ts, 10, 72))
40+
>Key : Symbol(Key, Decl(intersectionTypeInference2.ts, 10, 22))
41+
>T : Symbol(T, Decl(intersectionTypeInference2.ts, 10, 20))
42+
>Key : Symbol(Key, Decl(intersectionTypeInference2.ts, 10, 22))
43+
44+
declare const obj: { a: string } & { b: string };
45+
>obj : Symbol(obj, Decl(intersectionTypeInference2.ts, 12, 13))
46+
>a : Symbol(a, Decl(intersectionTypeInference2.ts, 12, 20))
47+
>b : Symbol(b, Decl(intersectionTypeInference2.ts, 12, 36))
48+
49+
f2(obj, 'a');
50+
>f2 : Symbol(f2, Decl(intersectionTypeInference2.ts, 6, 5))
51+
>obj : Symbol(obj, Decl(intersectionTypeInference2.ts, 12, 13))
52+
53+
f2(obj, 'b');
54+
>f2 : Symbol(f2, Decl(intersectionTypeInference2.ts, 6, 5))
55+
>obj : Symbol(obj, Decl(intersectionTypeInference2.ts, 12, 13))
56+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
=== tests/cases/conformance/types/intersection/intersectionTypeInference2.ts ===
2+
declare function f<T>(x: { prop: T }): T;
3+
>f : <T>(x: { prop: T; }) => T
4+
>T : T
5+
>x : { prop: T; }
6+
>prop : T
7+
>T : T
8+
>T : T
9+
10+
declare const a: { prop: string } & { prop: number };
11+
>a : { prop: string; } & { prop: number; }
12+
>prop : string
13+
>prop : number
14+
15+
declare const b: { prop: string & number };
16+
>b : { prop: string & number; }
17+
>prop : string & number
18+
19+
f(a); // string & number
20+
>f(a) : string & number
21+
>f : <T>(x: { prop: T; }) => T
22+
>a : { prop: string; } & { prop: number; }
23+
24+
f(b); // string & number
25+
>f(b) : string & number
26+
>f : <T>(x: { prop: T; }) => T
27+
>b : { prop: string & number; }
28+
29+
// Repro from #18354
30+
31+
declare function f2<T, Key extends keyof T>(obj: {[K in keyof T]: T[K]}, key: Key): T[Key];
32+
>f2 : <T, Key extends keyof T>(obj: { [K in keyof T]: T[K]; }, key: Key) => T[Key]
33+
>T : T
34+
>Key : Key
35+
>T : T
36+
>obj : { [K in keyof T]: T[K]; }
37+
>K : K
38+
>T : T
39+
>T : T
40+
>K : K
41+
>key : Key
42+
>Key : Key
43+
>T : T
44+
>Key : Key
45+
46+
declare const obj: { a: string } & { b: string };
47+
>obj : { a: string; } & { b: string; }
48+
>a : string
49+
>b : string
50+
51+
f2(obj, 'a');
52+
>f2(obj, 'a') : string
53+
>f2 : <T, Key extends keyof T>(obj: { [K in keyof T]: T[K]; }, key: Key) => T[Key]
54+
>obj : { a: string; } & { b: string; }
55+
>'a' : "a"
56+
57+
f2(obj, 'b');
58+
>f2(obj, 'b') : string
59+
>f2 : <T, Key extends keyof T>(obj: { [K in keyof T]: T[K]; }, key: Key) => T[Key]
60+
>obj : { a: string; } & { b: string; }
61+
>'b' : "b"
62+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
declare function f<T>(x: { prop: T }): T;
2+
3+
declare const a: { prop: string } & { prop: number };
4+
declare const b: { prop: string & number };
5+
6+
f(a); // string & number
7+
f(b); // string & number
8+
9+
// Repro from #18354
10+
11+
declare function f2<T, Key extends keyof T>(obj: {[K in keyof T]: T[K]}, key: Key): T[Key];
12+
13+
declare const obj: { a: string } & { b: string };
14+
f2(obj, 'a');
15+
f2(obj, 'b');

tests/cases/fourslash/tsxQuickInfo6.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@
1515

1616
verify.quickInfos({
1717
1: "function ComponentSpecific<number>(l: {\n prop: number;\n}): any",
18-
2: "function ComponentSpecific<number>(l: {\n prop: number;\n}): any"
18+
2: "function ComponentSpecific<number & \"hello\">(l: {\n prop: number & \"hello\";\n}): any"
1919
});

tests/cases/fourslash/tsxQuickInfo7.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ verify.quickInfos({
2424
3: "function OverloadComponent<boolean, string>(attr: {\n b: string;\n a: boolean;\n}): any (+2 overloads)",
2525
4: "function OverloadComponent<number>(attr: {\n b: number;\n a?: string;\n \"ignore-prop\": boolean;\n}): any (+2 overloads)",
2626
5: "function OverloadComponent(): any (+2 overloads)",
27-
6: "function OverloadComponent<boolean, string>(attr: {\n b: string;\n a: boolean;\n}): any (+2 overloads)",
28-
7: "function OverloadComponent<boolean, number>(attr: {\n b: number;\n a: boolean;\n}): any (+2 overloads)",
27+
6: "function OverloadComponent<boolean, string & number>(attr: {\n b: string & number;\n a: boolean;\n}): any (+2 overloads)",
28+
7: "function OverloadComponent<boolean, number & string>(attr: {\n b: number & string;\n a: boolean;\n}): any (+2 overloads)",
2929
});

0 commit comments

Comments
 (0)