From 52a9cfb0a9de3f0c0f36a77bb976330a0a57f6df Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 6 Feb 2019 14:23:49 -0800 Subject: [PATCH 1/7] Infer to partially homomorphic mapped types (such as Pick) --- src/compiler/checker.ts | 45 ++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ce06e84b2fd26..aa5007065fc8e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14570,11 +14570,24 @@ namespace ts { return undefined; } - function inferFromMappedTypeConstraint(source: Type, target: Type, constraintType: Type): boolean { + function inferToHomomorphicMappedType(source: Type, target: MappedType, constraintType: IndexType) { + const inference = getInferenceInfoForType(constraintType.type); + if (inference && !inference.isFixed) { + const inferredType = inferTypeForHomomorphicMappedType(source, target, constraintType); + if (inferredType) { + const savePriority = priority; + priority |= InferencePriority.HomomorphicMappedType; + inferFromTypes(inferredType, inference.typeParameter); + priority = savePriority; + } + } + } + + function inferToMappedType(source: Type, target: MappedType, constraintType: Type): boolean { if (constraintType.flags & TypeFlags.Union) { let result = false; for (const type of (constraintType as UnionType).types) { - result = inferFromMappedTypeConstraint(source, target, type) || result; + result = inferToMappedType(source, target, type) || result; } return result; } @@ -14583,31 +14596,31 @@ namespace ts { // where T is a type variable. Use inferTypeForHomomorphicMappedType to infer a suitable source // type and then make a secondary inference from that type to T. We make a secondary inference // such that direct inferences to T get priority over inferences to Partial, for example. - const inference = getInferenceInfoForType((constraintType).type); - if (inference && !inference.isFixed) { - const inferredType = inferTypeForHomomorphicMappedType(source, target, constraintType as IndexType); - if (inferredType) { - const savePriority = priority; - priority |= InferencePriority.HomomorphicMappedType; - inferFromTypes(inferredType, inference.typeParameter); - priority = savePriority; - } - } + inferToHomomorphicMappedType(source, target, constraintType); return true; } if (constraintType.flags & TypeFlags.TypeParameter) { - // We're inferring from some source type S to a mapped type { [P in T]: X }, where T is a type - // parameter. Infer from 'keyof S' to T and infer from a union of each property type in S to X. + // We're inferring from some source type S to a mapped type { [P in K]: X }, where K is a type + // parameter. First infer from 'keyof S' to K. const savePriority = priority; priority |= InferencePriority.MappedTypeConstraint; inferFromTypes(getIndexType(source), constraintType); priority = savePriority; + // If K is constrained to an index type keyof T, where T is a type parameter, proceed to make + // the same inferences as we would for a homomorphic mapped type { [P in keyof T]: X } (this + // enables us to make meaningful inferences when the target is a Pick). Otherwise, infer + // from a union of the property types in the source to the template type X. + const extendedConstraint = getConstraintOfType(constraintType); + if (extendedConstraint && extendedConstraint.flags & TypeFlags.Index) { + inferToHomomorphicMappedType(source, target, extendedConstraint); + return true; + } const valueTypes = compact([ getIndexTypeOfType(source, IndexKind.String), getIndexTypeOfType(source, IndexKind.Number), ...map(getPropertiesOfType(source), getTypeOfSymbol) ]); - inferFromTypes(getUnionType(valueTypes), getTemplateTypeFromMappedType(target)); + inferFromTypes(getUnionType(valueTypes), getTemplateTypeFromMappedType(target)); return true; } return false; @@ -14622,7 +14635,7 @@ namespace ts { } if (getObjectFlags(target) & ObjectFlags.Mapped) { const constraintType = getConstraintTypeFromMappedType(target); - if (inferFromMappedTypeConstraint(source, target, constraintType)) { + if (inferToMappedType(source, target, constraintType)) { return; } } From 62c62f4f87bfcf96e3f0e0500b453187b39f3c89 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 6 Feb 2019 15:41:43 -0800 Subject: [PATCH 2/7] Add tests --- .../mapped/isomorphicMappedTypeInference.ts | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/cases/conformance/types/mapped/isomorphicMappedTypeInference.ts b/tests/cases/conformance/types/mapped/isomorphicMappedTypeInference.ts index 14bb765a84011..534d50c367e12 100644 --- a/tests/cases/conformance/types/mapped/isomorphicMappedTypeInference.ts +++ b/tests/cases/conformance/types/mapped/isomorphicMappedTypeInference.ts @@ -152,4 +152,27 @@ var g2 = applySpec({ foo: { bar: { baz: (x: any) => true } } }); const foo = (object: T, partial: Partial) => object; let o = {a: 5, b: 7}; foo(o, {b: 9}); -o = foo(o, {b: 9}); \ No newline at end of file +o = foo(o, {b: 9}); + +// Inferring to { [P in K]: X }, where K extends keyof T, produces same inferences as +// inferring to { [P in keyof T]: X }. + +declare function f20(obj: Pick): T; +declare function f21(obj: Pick): K; +declare function f22(obj: Boxified>): T; + +let x0 = f20({ foo: 42, bar: "hello" }); +let x1 = f21({ foo: 42, bar: "hello" }); +let x2 = f22({ foo: { value: 42} , bar: { value: "hello" } }); + +// Repro from #29765 + +function getProps(obj: T, list: K[]): Pick { + return {} as any; +} + +const myAny: any = {}; + +const o1 = getProps(myAny, ['foo', 'bar']); + +const o2: { foo: any; bar: any } = getProps(myAny, ['foo', 'bar']); From 262e3c1ae294cef6e1075fa53a4d60481c700494 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 6 Feb 2019 15:41:51 -0800 Subject: [PATCH 3/7] Accept new baselines --- .../isomorphicMappedTypeInference.js | 55 +++++++++++- .../isomorphicMappedTypeInference.symbols | 90 +++++++++++++++++++ .../isomorphicMappedTypeInference.types | 85 ++++++++++++++++++ 3 files changed, 229 insertions(+), 1 deletion(-) diff --git a/tests/baselines/reference/isomorphicMappedTypeInference.js b/tests/baselines/reference/isomorphicMappedTypeInference.js index 589122444323a..6cfc2ec7350da 100644 --- a/tests/baselines/reference/isomorphicMappedTypeInference.js +++ b/tests/baselines/reference/isomorphicMappedTypeInference.js @@ -149,7 +149,31 @@ var g2 = applySpec({ foo: { bar: { baz: (x: any) => true } } }); const foo = (object: T, partial: Partial) => object; let o = {a: 5, b: 7}; foo(o, {b: 9}); -o = foo(o, {b: 9}); +o = foo(o, {b: 9}); + +// Inferring to { [P in K]: X }, where K extends keyof T, produces same inferences as +// inferring to { [P in keyof T]: X }. + +declare function f20(obj: Pick): T; +declare function f21(obj: Pick): K; +declare function f22(obj: Boxified>): T; + +let x0 = f20({ foo: 42, bar: "hello" }); +let x1 = f21({ foo: 42, bar: "hello" }); +let x2 = f22({ foo: { value: 42} , bar: { value: "hello" } }); + +// Repro from #29765 + +function getProps(obj: T, list: K[]): Pick { + return {} as any; +} + +const myAny: any = {}; + +const o1 = getProps(myAny, ['foo', 'bar']); + +const o2: { foo: any; bar: any } = getProps(myAny, ['foo', 'bar']); + //// [isomorphicMappedTypeInference.js] function box(x) { @@ -255,6 +279,16 @@ var foo = function (object, partial) { return object; }; var o = { a: 5, b: 7 }; foo(o, { b: 9 }); o = foo(o, { b: 9 }); +var x0 = f20({ foo: 42, bar: "hello" }); +var x1 = f21({ foo: 42, bar: "hello" }); +var x2 = f22({ foo: { value: 42 }, bar: { value: "hello" } }); +// Repro from #29765 +function getProps(obj, list) { + return {}; +} +var myAny = {}; +var o1 = getProps(myAny, ['foo', 'bar']); +var o2 = getProps(myAny, ['foo', 'bar']); //// [isomorphicMappedTypeInference.d.ts] @@ -323,3 +357,22 @@ declare let o: { a: number; b: number; }; +declare function f20(obj: Pick): T; +declare function f21(obj: Pick): K; +declare function f22(obj: Boxified>): T; +declare let x0: { + foo: number; + bar: string; +}; +declare let x1: "foo" | "bar"; +declare let x2: { + foo: number; + bar: string; +}; +declare function getProps(obj: T, list: K[]): Pick; +declare const myAny: any; +declare const o1: Pick; +declare const o2: { + foo: any; + bar: any; +}; diff --git a/tests/baselines/reference/isomorphicMappedTypeInference.symbols b/tests/baselines/reference/isomorphicMappedTypeInference.symbols index d36ebc7a4a517..6f999f91dc439 100644 --- a/tests/baselines/reference/isomorphicMappedTypeInference.symbols +++ b/tests/baselines/reference/isomorphicMappedTypeInference.symbols @@ -486,3 +486,93 @@ o = foo(o, {b: 9}); >o : Symbol(o, Decl(isomorphicMappedTypeInference.ts, 148, 3)) >b : Symbol(b, Decl(isomorphicMappedTypeInference.ts, 150, 12)) +// Inferring to { [P in K]: X }, where K extends keyof T, produces same inferences as +// inferring to { [P in keyof T]: X }. + +declare function f20(obj: Pick): T; +>f20 : Symbol(f20, Decl(isomorphicMappedTypeInference.ts, 150, 19)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 155, 21)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 155, 23)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 155, 21)) +>obj : Symbol(obj, Decl(isomorphicMappedTypeInference.ts, 155, 43)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 155, 21)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 155, 23)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 155, 21)) + +declare function f21(obj: Pick): K; +>f21 : Symbol(f21, Decl(isomorphicMappedTypeInference.ts, 155, 63)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 156, 21)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 156, 23)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 156, 21)) +>obj : Symbol(obj, Decl(isomorphicMappedTypeInference.ts, 156, 43)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 156, 21)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 156, 23)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 156, 23)) + +declare function f22(obj: Boxified>): T; +>f22 : Symbol(f22, Decl(isomorphicMappedTypeInference.ts, 156, 63)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 157, 21)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 157, 23)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 157, 21)) +>obj : Symbol(obj, Decl(isomorphicMappedTypeInference.ts, 157, 43)) +>Boxified : Symbol(Boxified, Decl(isomorphicMappedTypeInference.ts, 2, 1)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 157, 21)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 157, 23)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 157, 21)) + +let x0 = f20({ foo: 42, bar: "hello" }); +>x0 : Symbol(x0, Decl(isomorphicMappedTypeInference.ts, 159, 3)) +>f20 : Symbol(f20, Decl(isomorphicMappedTypeInference.ts, 150, 19)) +>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 159, 14)) +>bar : Symbol(bar, Decl(isomorphicMappedTypeInference.ts, 159, 23)) + +let x1 = f21({ foo: 42, bar: "hello" }); +>x1 : Symbol(x1, Decl(isomorphicMappedTypeInference.ts, 160, 3)) +>f21 : Symbol(f21, Decl(isomorphicMappedTypeInference.ts, 155, 63)) +>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 160, 14)) +>bar : Symbol(bar, Decl(isomorphicMappedTypeInference.ts, 160, 23)) + +let x2 = f22({ foo: { value: 42} , bar: { value: "hello" } }); +>x2 : Symbol(x2, Decl(isomorphicMappedTypeInference.ts, 161, 3)) +>f22 : Symbol(f22, Decl(isomorphicMappedTypeInference.ts, 156, 63)) +>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 161, 14)) +>value : Symbol(value, Decl(isomorphicMappedTypeInference.ts, 161, 21)) +>bar : Symbol(bar, Decl(isomorphicMappedTypeInference.ts, 161, 34)) +>value : Symbol(value, Decl(isomorphicMappedTypeInference.ts, 161, 41)) + +// Repro from #29765 + +function getProps(obj: T, list: K[]): Pick { +>getProps : Symbol(getProps, Decl(isomorphicMappedTypeInference.ts, 161, 62)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 165, 18)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 165, 20)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 165, 18)) +>obj : Symbol(obj, Decl(isomorphicMappedTypeInference.ts, 165, 40)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 165, 18)) +>list : Symbol(list, Decl(isomorphicMappedTypeInference.ts, 165, 47)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 165, 20)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 165, 18)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 165, 20)) + + return {} as any; +} + +const myAny: any = {}; +>myAny : Symbol(myAny, Decl(isomorphicMappedTypeInference.ts, 169, 5)) + +const o1 = getProps(myAny, ['foo', 'bar']); +>o1 : Symbol(o1, Decl(isomorphicMappedTypeInference.ts, 171, 5)) +>getProps : Symbol(getProps, Decl(isomorphicMappedTypeInference.ts, 161, 62)) +>myAny : Symbol(myAny, Decl(isomorphicMappedTypeInference.ts, 169, 5)) + +const o2: { foo: any; bar: any } = getProps(myAny, ['foo', 'bar']); +>o2 : Symbol(o2, Decl(isomorphicMappedTypeInference.ts, 173, 5)) +>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 173, 11)) +>bar : Symbol(bar, Decl(isomorphicMappedTypeInference.ts, 173, 21)) +>getProps : Symbol(getProps, Decl(isomorphicMappedTypeInference.ts, 161, 62)) +>myAny : Symbol(myAny, Decl(isomorphicMappedTypeInference.ts, 169, 5)) + diff --git a/tests/baselines/reference/isomorphicMappedTypeInference.types b/tests/baselines/reference/isomorphicMappedTypeInference.types index 4488fa27daf6c..b37175b5eed28 100644 --- a/tests/baselines/reference/isomorphicMappedTypeInference.types +++ b/tests/baselines/reference/isomorphicMappedTypeInference.types @@ -507,3 +507,88 @@ o = foo(o, {b: 9}); >b : number >9 : 9 +// Inferring to { [P in K]: X }, where K extends keyof T, produces same inferences as +// inferring to { [P in keyof T]: X }. + +declare function f20(obj: Pick): T; +>f20 : (obj: Pick) => T +>obj : Pick + +declare function f21(obj: Pick): K; +>f21 : (obj: Pick) => K +>obj : Pick + +declare function f22(obj: Boxified>): T; +>f22 : (obj: Boxified>) => T +>obj : Boxified> + +let x0 = f20({ foo: 42, bar: "hello" }); +>x0 : { foo: number; bar: string; } +>f20({ foo: 42, bar: "hello" }) : { foo: number; bar: string; } +>f20 : (obj: Pick) => T +>{ foo: 42, bar: "hello" } : { foo: number; bar: string; } +>foo : number +>42 : 42 +>bar : string +>"hello" : "hello" + +let x1 = f21({ foo: 42, bar: "hello" }); +>x1 : "foo" | "bar" +>f21({ foo: 42, bar: "hello" }) : "foo" | "bar" +>f21 : (obj: Pick) => K +>{ foo: 42, bar: "hello" } : { foo: number; bar: string; } +>foo : number +>42 : 42 +>bar : string +>"hello" : "hello" + +let x2 = f22({ foo: { value: 42} , bar: { value: "hello" } }); +>x2 : { foo: number; bar: string; } +>f22({ foo: { value: 42} , bar: { value: "hello" } }) : { foo: number; bar: string; } +>f22 : (obj: Boxified>) => T +>{ foo: { value: 42} , bar: { value: "hello" } } : { foo: { value: number; }; bar: { value: string; }; } +>foo : { value: number; } +>{ value: 42} : { value: number; } +>value : number +>42 : 42 +>bar : { value: string; } +>{ value: "hello" } : { value: string; } +>value : string +>"hello" : "hello" + +// Repro from #29765 + +function getProps(obj: T, list: K[]): Pick { +>getProps : (obj: T, list: K[]) => Pick +>obj : T +>list : K[] + + return {} as any; +>{} as any : any +>{} : {} +} + +const myAny: any = {}; +>myAny : any +>{} : {} + +const o1 = getProps(myAny, ['foo', 'bar']); +>o1 : Pick +>getProps(myAny, ['foo', 'bar']) : Pick +>getProps : (obj: T, list: K[]) => Pick +>myAny : any +>['foo', 'bar'] : ("foo" | "bar")[] +>'foo' : "foo" +>'bar' : "bar" + +const o2: { foo: any; bar: any } = getProps(myAny, ['foo', 'bar']); +>o2 : { foo: any; bar: any; } +>foo : any +>bar : any +>getProps(myAny, ['foo', 'bar']) : Pick +>getProps : (obj: T, list: K[]) => Pick +>myAny : any +>['foo', 'bar'] : ("foo" | "bar")[] +>'foo' : "foo" +>'bar' : "bar" + From f46c0a45979669daf2067c3990bf604a7d35dcaf Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 8 Feb 2019 06:49:13 -0800 Subject: [PATCH 4/7] Process more complex constraints as per CR feedback --- src/compiler/checker.ts | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index aa5007065fc8e..bdb645a00036a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14570,19 +14570,8 @@ namespace ts { return undefined; } - function inferToHomomorphicMappedType(source: Type, target: MappedType, constraintType: IndexType) { - const inference = getInferenceInfoForType(constraintType.type); - if (inference && !inference.isFixed) { - const inferredType = inferTypeForHomomorphicMappedType(source, target, constraintType); - if (inferredType) { - const savePriority = priority; - priority |= InferencePriority.HomomorphicMappedType; - inferFromTypes(inferredType, inference.typeParameter); - priority = savePriority; - } - } - } - + // target: { [P in 'a' | 'b' | keyof T | keyof U]: XXX } + // source: { a: xxx, b: xxx, c: xxx, d: xxx } function inferToMappedType(source: Type, target: MappedType, constraintType: Type): boolean { if (constraintType.flags & TypeFlags.Union) { let result = false; @@ -14596,7 +14585,16 @@ namespace ts { // where T is a type variable. Use inferTypeForHomomorphicMappedType to infer a suitable source // type and then make a secondary inference from that type to T. We make a secondary inference // such that direct inferences to T get priority over inferences to Partial, for example. - inferToHomomorphicMappedType(source, target, constraintType); + const inference = getInferenceInfoForType((constraintType).type); + if (inference && !inference.isFixed) { + const inferredType = inferTypeForHomomorphicMappedType(source, target, constraintType); + if (inferredType) { + const savePriority = priority; + priority |= InferencePriority.HomomorphicMappedType; + inferFromTypes(inferredType, inference.typeParameter); + priority = savePriority; + } + } return true; } if (constraintType.flags & TypeFlags.TypeParameter) { @@ -14606,15 +14604,16 @@ namespace ts { priority |= InferencePriority.MappedTypeConstraint; inferFromTypes(getIndexType(source), constraintType); priority = savePriority; - // If K is constrained to an index type keyof T, where T is a type parameter, proceed to make - // the same inferences as we would for a homomorphic mapped type { [P in keyof T]: X } (this - // enables us to make meaningful inferences when the target is a Pick). Otherwise, infer - // from a union of the property types in the source to the template type X. + // If K is constrained to a type C, also infer to C. Thus, for a mapped type { [P in K]: X }, + // where K extends keyof T, we make the same inferences as for a homomorphic mapped type + // { [P in keyof T]: X }. This enables us to make meaningful inferences when the target is a + // Pick. const extendedConstraint = getConstraintOfType(constraintType); - if (extendedConstraint && extendedConstraint.flags & TypeFlags.Index) { - inferToHomomorphicMappedType(source, target, extendedConstraint); + if (extendedConstraint && inferToMappedType(source, target, extendedConstraint)) { return true; } + // If no inferences can be made to K's constraint, infer from a union of the property types + // in the source to the template type X. const valueTypes = compact([ getIndexTypeOfType(source, IndexKind.String), getIndexTypeOfType(source, IndexKind.Number), From e49320d1db82ae4e281914ab3b6c4d101da4e16d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 8 Feb 2019 06:49:26 -0800 Subject: [PATCH 5/7] Add more tests --- .../conformance/types/mapped/isomorphicMappedTypeInference.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/cases/conformance/types/mapped/isomorphicMappedTypeInference.ts b/tests/cases/conformance/types/mapped/isomorphicMappedTypeInference.ts index 534d50c367e12..031cf840d33f4 100644 --- a/tests/cases/conformance/types/mapped/isomorphicMappedTypeInference.ts +++ b/tests/cases/conformance/types/mapped/isomorphicMappedTypeInference.ts @@ -160,10 +160,14 @@ o = foo(o, {b: 9}); declare function f20(obj: Pick): T; declare function f21(obj: Pick): K; declare function f22(obj: Boxified>): T; +declare function f23(obj: Pick): T; +declare function f24(obj: Pick): T & U; let x0 = f20({ foo: 42, bar: "hello" }); let x1 = f21({ foo: 42, bar: "hello" }); let x2 = f22({ foo: { value: 42} , bar: { value: "hello" } }); +let x3 = f23({ foo: 42, bar: "hello" }); +let x4 = f24({ foo: 42, bar: "hello" }); // Repro from #29765 From 8652158ead4af506a604d70ad80becba7ddccea9 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 8 Feb 2019 06:49:33 -0800 Subject: [PATCH 6/7] Accept new baselines --- .../isomorphicMappedTypeInference.js | 19 ++++ .../isomorphicMappedTypeInference.symbols | 100 ++++++++++++------ .../isomorphicMappedTypeInference.types | 28 +++++ 3 files changed, 117 insertions(+), 30 deletions(-) diff --git a/tests/baselines/reference/isomorphicMappedTypeInference.js b/tests/baselines/reference/isomorphicMappedTypeInference.js index 6cfc2ec7350da..aa904e9afa173 100644 --- a/tests/baselines/reference/isomorphicMappedTypeInference.js +++ b/tests/baselines/reference/isomorphicMappedTypeInference.js @@ -157,10 +157,14 @@ o = foo(o, {b: 9}); declare function f20(obj: Pick): T; declare function f21(obj: Pick): K; declare function f22(obj: Boxified>): T; +declare function f23(obj: Pick): T; +declare function f24(obj: Pick): T & U; let x0 = f20({ foo: 42, bar: "hello" }); let x1 = f21({ foo: 42, bar: "hello" }); let x2 = f22({ foo: { value: 42} , bar: { value: "hello" } }); +let x3 = f23({ foo: 42, bar: "hello" }); +let x4 = f24({ foo: 42, bar: "hello" }); // Repro from #29765 @@ -282,6 +286,8 @@ o = foo(o, { b: 9 }); var x0 = f20({ foo: 42, bar: "hello" }); var x1 = f21({ foo: 42, bar: "hello" }); var x2 = f22({ foo: { value: 42 }, bar: { value: "hello" } }); +var x3 = f23({ foo: 42, bar: "hello" }); +var x4 = f24({ foo: 42, bar: "hello" }); // Repro from #29765 function getProps(obj, list) { return {}; @@ -360,6 +366,8 @@ declare let o: { declare function f20(obj: Pick): T; declare function f21(obj: Pick): K; declare function f22(obj: Boxified>): T; +declare function f23(obj: Pick): T; +declare function f24(obj: Pick): T & U; declare let x0: { foo: number; bar: string; @@ -369,6 +377,17 @@ declare let x2: { foo: number; bar: string; }; +declare let x3: { + foo: number; + bar: string; +}; +declare let x4: { + foo: number; + bar: string; +} & { + foo: number; + bar: string; +}; declare function getProps(obj: T, list: K[]): Pick; declare const myAny: any; declare const o1: Pick; diff --git a/tests/baselines/reference/isomorphicMappedTypeInference.symbols b/tests/baselines/reference/isomorphicMappedTypeInference.symbols index 6f999f91dc439..3192be13ff634 100644 --- a/tests/baselines/reference/isomorphicMappedTypeInference.symbols +++ b/tests/baselines/reference/isomorphicMappedTypeInference.symbols @@ -523,56 +523,96 @@ declare function f22(obj: Boxified>): T; >K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 157, 23)) >T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 157, 21)) +declare function f23(obj: Pick): T; +>f23 : Symbol(f23, Decl(isomorphicMappedTypeInference.ts, 157, 73)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 158, 21)) +>U : Symbol(U, Decl(isomorphicMappedTypeInference.ts, 158, 23)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 158, 21)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 158, 42)) +>U : Symbol(U, Decl(isomorphicMappedTypeInference.ts, 158, 23)) +>obj : Symbol(obj, Decl(isomorphicMappedTypeInference.ts, 158, 56)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 158, 21)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 158, 42)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 158, 21)) + +declare function f24(obj: Pick): T & U; +>f24 : Symbol(f24, Decl(isomorphicMappedTypeInference.ts, 158, 76)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 159, 21)) +>U : Symbol(U, Decl(isomorphicMappedTypeInference.ts, 159, 23)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 159, 26)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 159, 21)) +>U : Symbol(U, Decl(isomorphicMappedTypeInference.ts, 159, 23)) +>obj : Symbol(obj, Decl(isomorphicMappedTypeInference.ts, 159, 56)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 159, 21)) +>U : Symbol(U, Decl(isomorphicMappedTypeInference.ts, 159, 23)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 159, 26)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 159, 21)) +>U : Symbol(U, Decl(isomorphicMappedTypeInference.ts, 159, 23)) + let x0 = f20({ foo: 42, bar: "hello" }); ->x0 : Symbol(x0, Decl(isomorphicMappedTypeInference.ts, 159, 3)) +>x0 : Symbol(x0, Decl(isomorphicMappedTypeInference.ts, 161, 3)) >f20 : Symbol(f20, Decl(isomorphicMappedTypeInference.ts, 150, 19)) ->foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 159, 14)) ->bar : Symbol(bar, Decl(isomorphicMappedTypeInference.ts, 159, 23)) +>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 161, 14)) +>bar : Symbol(bar, Decl(isomorphicMappedTypeInference.ts, 161, 23)) let x1 = f21({ foo: 42, bar: "hello" }); ->x1 : Symbol(x1, Decl(isomorphicMappedTypeInference.ts, 160, 3)) +>x1 : Symbol(x1, Decl(isomorphicMappedTypeInference.ts, 162, 3)) >f21 : Symbol(f21, Decl(isomorphicMappedTypeInference.ts, 155, 63)) ->foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 160, 14)) ->bar : Symbol(bar, Decl(isomorphicMappedTypeInference.ts, 160, 23)) +>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 162, 14)) +>bar : Symbol(bar, Decl(isomorphicMappedTypeInference.ts, 162, 23)) let x2 = f22({ foo: { value: 42} , bar: { value: "hello" } }); ->x2 : Symbol(x2, Decl(isomorphicMappedTypeInference.ts, 161, 3)) +>x2 : Symbol(x2, Decl(isomorphicMappedTypeInference.ts, 163, 3)) >f22 : Symbol(f22, Decl(isomorphicMappedTypeInference.ts, 156, 63)) ->foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 161, 14)) ->value : Symbol(value, Decl(isomorphicMappedTypeInference.ts, 161, 21)) ->bar : Symbol(bar, Decl(isomorphicMappedTypeInference.ts, 161, 34)) ->value : Symbol(value, Decl(isomorphicMappedTypeInference.ts, 161, 41)) +>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 163, 14)) +>value : Symbol(value, Decl(isomorphicMappedTypeInference.ts, 163, 21)) +>bar : Symbol(bar, Decl(isomorphicMappedTypeInference.ts, 163, 34)) +>value : Symbol(value, Decl(isomorphicMappedTypeInference.ts, 163, 41)) + +let x3 = f23({ foo: 42, bar: "hello" }); +>x3 : Symbol(x3, Decl(isomorphicMappedTypeInference.ts, 164, 3)) +>f23 : Symbol(f23, Decl(isomorphicMappedTypeInference.ts, 157, 73)) +>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 164, 14)) +>bar : Symbol(bar, Decl(isomorphicMappedTypeInference.ts, 164, 23)) + +let x4 = f24({ foo: 42, bar: "hello" }); +>x4 : Symbol(x4, Decl(isomorphicMappedTypeInference.ts, 165, 3)) +>f24 : Symbol(f24, Decl(isomorphicMappedTypeInference.ts, 158, 76)) +>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 165, 14)) +>bar : Symbol(bar, Decl(isomorphicMappedTypeInference.ts, 165, 23)) // Repro from #29765 function getProps(obj: T, list: K[]): Pick { ->getProps : Symbol(getProps, Decl(isomorphicMappedTypeInference.ts, 161, 62)) ->T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 165, 18)) ->K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 165, 20)) ->T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 165, 18)) ->obj : Symbol(obj, Decl(isomorphicMappedTypeInference.ts, 165, 40)) ->T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 165, 18)) ->list : Symbol(list, Decl(isomorphicMappedTypeInference.ts, 165, 47)) ->K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 165, 20)) +>getProps : Symbol(getProps, Decl(isomorphicMappedTypeInference.ts, 165, 40)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 169, 18)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 169, 20)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 169, 18)) +>obj : Symbol(obj, Decl(isomorphicMappedTypeInference.ts, 169, 40)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 169, 18)) +>list : Symbol(list, Decl(isomorphicMappedTypeInference.ts, 169, 47)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 169, 20)) >Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 165, 18)) ->K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 165, 20)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 169, 18)) +>K : Symbol(K, Decl(isomorphicMappedTypeInference.ts, 169, 20)) return {} as any; } const myAny: any = {}; ->myAny : Symbol(myAny, Decl(isomorphicMappedTypeInference.ts, 169, 5)) +>myAny : Symbol(myAny, Decl(isomorphicMappedTypeInference.ts, 173, 5)) const o1 = getProps(myAny, ['foo', 'bar']); ->o1 : Symbol(o1, Decl(isomorphicMappedTypeInference.ts, 171, 5)) ->getProps : Symbol(getProps, Decl(isomorphicMappedTypeInference.ts, 161, 62)) ->myAny : Symbol(myAny, Decl(isomorphicMappedTypeInference.ts, 169, 5)) +>o1 : Symbol(o1, Decl(isomorphicMappedTypeInference.ts, 175, 5)) +>getProps : Symbol(getProps, Decl(isomorphicMappedTypeInference.ts, 165, 40)) +>myAny : Symbol(myAny, Decl(isomorphicMappedTypeInference.ts, 173, 5)) const o2: { foo: any; bar: any } = getProps(myAny, ['foo', 'bar']); ->o2 : Symbol(o2, Decl(isomorphicMappedTypeInference.ts, 173, 5)) ->foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 173, 11)) ->bar : Symbol(bar, Decl(isomorphicMappedTypeInference.ts, 173, 21)) ->getProps : Symbol(getProps, Decl(isomorphicMappedTypeInference.ts, 161, 62)) ->myAny : Symbol(myAny, Decl(isomorphicMappedTypeInference.ts, 169, 5)) +>o2 : Symbol(o2, Decl(isomorphicMappedTypeInference.ts, 177, 5)) +>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 177, 11)) +>bar : Symbol(bar, Decl(isomorphicMappedTypeInference.ts, 177, 21)) +>getProps : Symbol(getProps, Decl(isomorphicMappedTypeInference.ts, 165, 40)) +>myAny : Symbol(myAny, Decl(isomorphicMappedTypeInference.ts, 173, 5)) diff --git a/tests/baselines/reference/isomorphicMappedTypeInference.types b/tests/baselines/reference/isomorphicMappedTypeInference.types index b37175b5eed28..1f1fa0d200a0c 100644 --- a/tests/baselines/reference/isomorphicMappedTypeInference.types +++ b/tests/baselines/reference/isomorphicMappedTypeInference.types @@ -522,6 +522,14 @@ declare function f22(obj: Boxified>): T; >f22 : (obj: Boxified>) => T >obj : Boxified> +declare function f23(obj: Pick): T; +>f23 : (obj: Pick) => T +>obj : Pick + +declare function f24(obj: Pick): T & U; +>f24 : (obj: Pick) => T & U +>obj : Pick + let x0 = f20({ foo: 42, bar: "hello" }); >x0 : { foo: number; bar: string; } >f20({ foo: 42, bar: "hello" }) : { foo: number; bar: string; } @@ -556,6 +564,26 @@ let x2 = f22({ foo: { value: 42} , bar: { value: "hello" } }); >value : string >"hello" : "hello" +let x3 = f23({ foo: 42, bar: "hello" }); +>x3 : { foo: number; bar: string; } +>f23({ foo: 42, bar: "hello" }) : { foo: number; bar: string; } +>f23 : (obj: Pick) => T +>{ foo: 42, bar: "hello" } : { foo: number; bar: string; } +>foo : number +>42 : 42 +>bar : string +>"hello" : "hello" + +let x4 = f24({ foo: 42, bar: "hello" }); +>x4 : { foo: number; bar: string; } & { foo: number; bar: string; } +>f24({ foo: 42, bar: "hello" }) : { foo: number; bar: string; } & { foo: number; bar: string; } +>f24 : (obj: Pick) => T & U +>{ foo: 42, bar: "hello" } : { foo: number; bar: string; } +>foo : number +>42 : 42 +>bar : string +>"hello" : "hello" + // Repro from #29765 function getProps(obj: T, list: K[]): Pick { From 040401205ba51d036b9ec234ff2f2341ceac96b9 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 8 Feb 2019 06:53:39 -0800 Subject: [PATCH 7/7] Delete wayward comment --- src/compiler/checker.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bdb645a00036a..b550710861c72 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14570,8 +14570,6 @@ namespace ts { return undefined; } - // target: { [P in 'a' | 'b' | keyof T | keyof U]: XXX } - // source: { a: xxx, b: xxx, c: xxx, d: xxx } function inferToMappedType(source: Type, target: MappedType, constraintType: Type): boolean { if (constraintType.flags & TypeFlags.Union) { let result = false;