Merge pull request #18363 from Microsoft/fixIntersectionInference

Fix intersection inference
This commit is contained in:
Anders Hejlsberg 2017-09-11 20:46:43 +01:00 committed by GitHub
commit d65a3e1c67
7 changed files with 162 additions and 6 deletions

View file

@ -10579,7 +10579,7 @@ namespace ts {
priority = savePriority;
}
}
else if (source.flags & TypeFlags.UnionOrIntersection) {
else if (source.flags & TypeFlags.Union) {
// Source is a union or intersection type, infer from each constituent type
const sourceTypes = (<UnionOrIntersectionType>source).types;
for (const sourceType of sourceTypes) {
@ -10588,7 +10588,7 @@ namespace ts {
}
else {
source = getApparentType(source);
if (source.flags & TypeFlags.Object) {
if (source.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
const key = source.id + "," + target.id;
if (visited && visited.get(key)) {
return;
@ -10668,7 +10668,7 @@ namespace ts {
function inferFromProperties(source: Type, target: Type) {
const properties = getPropertiesOfObjectType(target);
for (const targetProp of properties) {
const sourceProp = getPropertyOfObjectType(source, targetProp.escapedName);
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
if (sourceProp) {
inferFromTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp));
}

View file

@ -0,0 +1,23 @@
//// [intersectionTypeInference2.ts]
declare function f<T>(x: { prop: T }): T;
declare const a: { prop: string } & { prop: number };
declare const b: { prop: string & number };
f(a); // string & number
f(b); // string & number
// Repro from #18354
declare function f2<T, Key extends keyof T>(obj: {[K in keyof T]: T[K]}, key: Key): T[Key];
declare const obj: { a: string } & { b: string };
f2(obj, 'a');
f2(obj, 'b');
//// [intersectionTypeInference2.js]
f(a); // string & number
f(b); // string & number
f2(obj, 'a');
f2(obj, 'b');

View file

@ -0,0 +1,56 @@
=== tests/cases/conformance/types/intersection/intersectionTypeInference2.ts ===
declare function f<T>(x: { prop: T }): T;
>f : Symbol(f, Decl(intersectionTypeInference2.ts, 0, 0))
>T : Symbol(T, Decl(intersectionTypeInference2.ts, 0, 19))
>x : Symbol(x, Decl(intersectionTypeInference2.ts, 0, 22))
>prop : Symbol(prop, Decl(intersectionTypeInference2.ts, 0, 26))
>T : Symbol(T, Decl(intersectionTypeInference2.ts, 0, 19))
>T : Symbol(T, Decl(intersectionTypeInference2.ts, 0, 19))
declare const a: { prop: string } & { prop: number };
>a : Symbol(a, Decl(intersectionTypeInference2.ts, 2, 13))
>prop : Symbol(prop, Decl(intersectionTypeInference2.ts, 2, 18))
>prop : Symbol(prop, Decl(intersectionTypeInference2.ts, 2, 37))
declare const b: { prop: string & number };
>b : Symbol(b, Decl(intersectionTypeInference2.ts, 3, 13))
>prop : Symbol(prop, Decl(intersectionTypeInference2.ts, 3, 18))
f(a); // string & number
>f : Symbol(f, Decl(intersectionTypeInference2.ts, 0, 0))
>a : Symbol(a, Decl(intersectionTypeInference2.ts, 2, 13))
f(b); // string & number
>f : Symbol(f, Decl(intersectionTypeInference2.ts, 0, 0))
>b : Symbol(b, Decl(intersectionTypeInference2.ts, 3, 13))
// Repro from #18354
declare function f2<T, Key extends keyof T>(obj: {[K in keyof T]: T[K]}, key: Key): T[Key];
>f2 : Symbol(f2, Decl(intersectionTypeInference2.ts, 6, 5))
>T : Symbol(T, Decl(intersectionTypeInference2.ts, 10, 20))
>Key : Symbol(Key, Decl(intersectionTypeInference2.ts, 10, 22))
>T : Symbol(T, Decl(intersectionTypeInference2.ts, 10, 20))
>obj : Symbol(obj, Decl(intersectionTypeInference2.ts, 10, 44))
>K : Symbol(K, Decl(intersectionTypeInference2.ts, 10, 51))
>T : Symbol(T, Decl(intersectionTypeInference2.ts, 10, 20))
>T : Symbol(T, Decl(intersectionTypeInference2.ts, 10, 20))
>K : Symbol(K, Decl(intersectionTypeInference2.ts, 10, 51))
>key : Symbol(key, Decl(intersectionTypeInference2.ts, 10, 72))
>Key : Symbol(Key, Decl(intersectionTypeInference2.ts, 10, 22))
>T : Symbol(T, Decl(intersectionTypeInference2.ts, 10, 20))
>Key : Symbol(Key, Decl(intersectionTypeInference2.ts, 10, 22))
declare const obj: { a: string } & { b: string };
>obj : Symbol(obj, Decl(intersectionTypeInference2.ts, 12, 13))
>a : Symbol(a, Decl(intersectionTypeInference2.ts, 12, 20))
>b : Symbol(b, Decl(intersectionTypeInference2.ts, 12, 36))
f2(obj, 'a');
>f2 : Symbol(f2, Decl(intersectionTypeInference2.ts, 6, 5))
>obj : Symbol(obj, Decl(intersectionTypeInference2.ts, 12, 13))
f2(obj, 'b');
>f2 : Symbol(f2, Decl(intersectionTypeInference2.ts, 6, 5))
>obj : Symbol(obj, Decl(intersectionTypeInference2.ts, 12, 13))

View file

@ -0,0 +1,62 @@
=== tests/cases/conformance/types/intersection/intersectionTypeInference2.ts ===
declare function f<T>(x: { prop: T }): T;
>f : <T>(x: { prop: T; }) => T
>T : T
>x : { prop: T; }
>prop : T
>T : T
>T : T
declare const a: { prop: string } & { prop: number };
>a : { prop: string; } & { prop: number; }
>prop : string
>prop : number
declare const b: { prop: string & number };
>b : { prop: string & number; }
>prop : string & number
f(a); // string & number
>f(a) : string & number
>f : <T>(x: { prop: T; }) => T
>a : { prop: string; } & { prop: number; }
f(b); // string & number
>f(b) : string & number
>f : <T>(x: { prop: T; }) => T
>b : { prop: string & number; }
// Repro from #18354
declare function f2<T, Key extends keyof T>(obj: {[K in keyof T]: T[K]}, key: Key): T[Key];
>f2 : <T, Key extends keyof T>(obj: { [K in keyof T]: T[K]; }, key: Key) => T[Key]
>T : T
>Key : Key
>T : T
>obj : { [K in keyof T]: T[K]; }
>K : K
>T : T
>T : T
>K : K
>key : Key
>Key : Key
>T : T
>Key : Key
declare const obj: { a: string } & { b: string };
>obj : { a: string; } & { b: string; }
>a : string
>b : string
f2(obj, 'a');
>f2(obj, 'a') : string
>f2 : <T, Key extends keyof T>(obj: { [K in keyof T]: T[K]; }, key: Key) => T[Key]
>obj : { a: string; } & { b: string; }
>'a' : "a"
f2(obj, 'b');
>f2(obj, 'b') : string
>f2 : <T, Key extends keyof T>(obj: { [K in keyof T]: T[K]; }, key: Key) => T[Key]
>obj : { a: string; } & { b: string; }
>'b' : "b"

View file

@ -0,0 +1,15 @@
declare function f<T>(x: { prop: T }): T;
declare const a: { prop: string } & { prop: number };
declare const b: { prop: string & number };
f(a); // string & number
f(b); // string & number
// Repro from #18354
declare function f2<T, Key extends keyof T>(obj: {[K in keyof T]: T[K]}, key: Key): T[Key];
declare const obj: { a: string } & { b: string };
f2(obj, 'a');
f2(obj, 'b');

View file

@ -15,5 +15,5 @@
verify.quickInfos({
1: "function ComponentSpecific<number>(l: {\n prop: number;\n}): any",
2: "function ComponentSpecific<number>(l: {\n prop: number;\n}): any"
2: "function ComponentSpecific<number & \"hello\">(l: {\n prop: number & \"hello\";\n}): any"
});

View file

@ -24,6 +24,6 @@ verify.quickInfos({
3: "function OverloadComponent<boolean, string>(attr: {\n b: string;\n a: boolean;\n}): any (+2 overloads)",
4: "function OverloadComponent<number>(attr: {\n b: number;\n a?: string;\n \"ignore-prop\": boolean;\n}): any (+2 overloads)",
5: "function OverloadComponent(): any (+2 overloads)",
6: "function OverloadComponent<boolean, string>(attr: {\n b: string;\n a: boolean;\n}): any (+2 overloads)",
7: "function OverloadComponent<boolean, number>(attr: {\n b: number;\n a: boolean;\n}): any (+2 overloads)",
6: "function OverloadComponent<boolean, string & number>(attr: {\n b: string & number;\n a: boolean;\n}): any (+2 overloads)",
7: "function OverloadComponent<boolean, number & string>(attr: {\n b: number & string;\n a: boolean;\n}): any (+2 overloads)",
});