From 5bb8d2a590899fc225df2472f41be1b52c41678e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 18 Jan 2018 17:15:48 -0800 Subject: [PATCH 1/3] Properly handle contravariant inferences in inferReverseMappedType --- src/compiler/checker.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 79430adf777bb..519a9f4cf40d5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11029,7 +11029,9 @@ namespace ts { const templateType = getTemplateTypeFromMappedType(target); const inference = createInferenceInfo(typeParameter); inferTypes([inference], sourceType, templateType); - return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) : emptyObjectType; + return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) : + inference.contraCandidates ? getCommonSubtype(inference.contraCandidates) : + emptyObjectType; } function getUnmatchedProperty(source: Type, target: Type, requireOptionalProperties: boolean) { From f6c79a631cf3ed3bfac4a1a61727acdb214ce7ba Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 18 Jan 2018 17:28:37 -0800 Subject: [PATCH 2/3] Add regression test --- tests/cases/compiler/reverseMappedContravariantInference.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/cases/compiler/reverseMappedContravariantInference.ts diff --git a/tests/cases/compiler/reverseMappedContravariantInference.ts b/tests/cases/compiler/reverseMappedContravariantInference.ts new file mode 100644 index 0000000000000..7b7492f6badc8 --- /dev/null +++ b/tests/cases/compiler/reverseMappedContravariantInference.ts @@ -0,0 +1,6 @@ +// @strict: true + +// Repro from #21273 + +declare function conforms(source: { [K in keyof T]: (val: T[K]) => boolean }): (value: T) => boolean; +conforms({ foo: (v: string) => false })({ foo: "hello" }); From 069eac09ecb3d6cbf6bd70fbf4dd09ee3e1623cd Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 18 Jan 2018 17:28:49 -0800 Subject: [PATCH 3/3] Accept new baselines --- .../reverseMappedContravariantInference.js | 11 ++++++++ ...everseMappedContravariantInference.symbols | 21 ++++++++++++++ .../reverseMappedContravariantInference.types | 28 +++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 tests/baselines/reference/reverseMappedContravariantInference.js create mode 100644 tests/baselines/reference/reverseMappedContravariantInference.symbols create mode 100644 tests/baselines/reference/reverseMappedContravariantInference.types diff --git a/tests/baselines/reference/reverseMappedContravariantInference.js b/tests/baselines/reference/reverseMappedContravariantInference.js new file mode 100644 index 0000000000000..7a3980e35aa4e --- /dev/null +++ b/tests/baselines/reference/reverseMappedContravariantInference.js @@ -0,0 +1,11 @@ +//// [reverseMappedContravariantInference.ts] +// Repro from #21273 + +declare function conforms(source: { [K in keyof T]: (val: T[K]) => boolean }): (value: T) => boolean; +conforms({ foo: (v: string) => false })({ foo: "hello" }); + + +//// [reverseMappedContravariantInference.js] +"use strict"; +// Repro from #21273 +conforms({ foo: function (v) { return false; } })({ foo: "hello" }); diff --git a/tests/baselines/reference/reverseMappedContravariantInference.symbols b/tests/baselines/reference/reverseMappedContravariantInference.symbols new file mode 100644 index 0000000000000..6f8744a99fee7 --- /dev/null +++ b/tests/baselines/reference/reverseMappedContravariantInference.symbols @@ -0,0 +1,21 @@ +=== tests/cases/compiler/reverseMappedContravariantInference.ts === +// Repro from #21273 + +declare function conforms(source: { [K in keyof T]: (val: T[K]) => boolean }): (value: T) => boolean; +>conforms : Symbol(conforms, Decl(reverseMappedContravariantInference.ts, 0, 0)) +>T : Symbol(T, Decl(reverseMappedContravariantInference.ts, 2, 26)) +>source : Symbol(source, Decl(reverseMappedContravariantInference.ts, 2, 29)) +>K : Symbol(K, Decl(reverseMappedContravariantInference.ts, 2, 40)) +>T : Symbol(T, Decl(reverseMappedContravariantInference.ts, 2, 26)) +>val : Symbol(val, Decl(reverseMappedContravariantInference.ts, 2, 56)) +>T : Symbol(T, Decl(reverseMappedContravariantInference.ts, 2, 26)) +>K : Symbol(K, Decl(reverseMappedContravariantInference.ts, 2, 40)) +>value : Symbol(value, Decl(reverseMappedContravariantInference.ts, 2, 83)) +>T : Symbol(T, Decl(reverseMappedContravariantInference.ts, 2, 26)) + +conforms({ foo: (v: string) => false })({ foo: "hello" }); +>conforms : Symbol(conforms, Decl(reverseMappedContravariantInference.ts, 0, 0)) +>foo : Symbol(foo, Decl(reverseMappedContravariantInference.ts, 3, 10)) +>v : Symbol(v, Decl(reverseMappedContravariantInference.ts, 3, 17)) +>foo : Symbol(foo, Decl(reverseMappedContravariantInference.ts, 3, 41)) + diff --git a/tests/baselines/reference/reverseMappedContravariantInference.types b/tests/baselines/reference/reverseMappedContravariantInference.types new file mode 100644 index 0000000000000..1decc716bbf33 --- /dev/null +++ b/tests/baselines/reference/reverseMappedContravariantInference.types @@ -0,0 +1,28 @@ +=== tests/cases/compiler/reverseMappedContravariantInference.ts === +// Repro from #21273 + +declare function conforms(source: { [K in keyof T]: (val: T[K]) => boolean }): (value: T) => boolean; +>conforms : (source: { [K in keyof T]: (val: T[K]) => boolean; }) => (value: T) => boolean +>T : T +>source : { [K in keyof T]: (val: T[K]) => boolean; } +>K : K +>T : T +>val : T[K] +>T : T +>K : K +>value : T +>T : T + +conforms({ foo: (v: string) => false })({ foo: "hello" }); +>conforms({ foo: (v: string) => false })({ foo: "hello" }) : boolean +>conforms({ foo: (v: string) => false }) : (value: { foo: any; }) => boolean +>conforms : (source: { [K in keyof T]: (val: T[K]) => boolean; }) => (value: T) => boolean +>{ foo: (v: string) => false } : { foo: (v: string) => boolean; } +>foo : (v: string) => boolean +>(v: string) => false : (v: string) => boolean +>v : string +>false : false +>{ foo: "hello" } : { foo: string; } +>foo : string +>"hello" : "hello" +