From 44a6c6cc6ff0f3c9bfedb9e0a69d68232c10fdcf Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 5 Aug 2017 10:09:44 -0700 Subject: [PATCH 1/3] { [P in K]: T } is related to { [x: string]: U } if T is related to U --- src/compiler/checker.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7913520bfdb..2cbaf0e1992 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9614,6 +9614,11 @@ namespace ts { if (sourceInfo) { return indexInfoRelatedTo(sourceInfo, targetInfo, reportErrors); } + if (isGenericMappedType(source)) { + // A generic mapped type { [P in K]: T } is related to an index signature { [x: string]: U } + // if T is related to U. + return kind === IndexKind.String && isRelatedTo(getTemplateTypeFromMappedType(source), targetInfo.type, reportErrors); + } if (isObjectLiteralType(source)) { let related = Ternary.True; if (kind === IndexKind.String) { From c938a2acdc4f7cfe19b628b074faa9b4e07ae736 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 5 Aug 2017 10:17:20 -0700 Subject: [PATCH 2/3] Add tests --- .../indexSignatureAndMappedType.errors.txt | 47 ++++++++++++ .../reference/indexSignatureAndMappedType.js | 73 +++++++++++++++++++ .../compiler/indexSignatureAndMappedType.ts | 35 +++++++++ 3 files changed, 155 insertions(+) create mode 100644 tests/baselines/reference/indexSignatureAndMappedType.errors.txt create mode 100644 tests/baselines/reference/indexSignatureAndMappedType.js create mode 100644 tests/cases/compiler/indexSignatureAndMappedType.ts diff --git a/tests/baselines/reference/indexSignatureAndMappedType.errors.txt b/tests/baselines/reference/indexSignatureAndMappedType.errors.txt new file mode 100644 index 00000000000..c8ae0494015 --- /dev/null +++ b/tests/baselines/reference/indexSignatureAndMappedType.errors.txt @@ -0,0 +1,47 @@ +tests/cases/compiler/indexSignatureAndMappedType.ts(6,5): error TS2322: Type '{ [key: string]: T; }' is not assignable to type 'Record'. +tests/cases/compiler/indexSignatureAndMappedType.ts(15,5): error TS2322: Type 'Record' is not assignable to type '{ [key: string]: T; }'. + Type 'U' is not assignable to type 'T'. +tests/cases/compiler/indexSignatureAndMappedType.ts(16,5): error TS2322: Type '{ [key: string]: T; }' is not assignable to type 'Record'. + + +==== tests/cases/compiler/indexSignatureAndMappedType.ts (3 errors) ==== + // A mapped type { [P in K]: X }, where K is a generic type, is related to + // { [key: string]: Y } if X is related to Y. + + function f1(x: { [key: string]: T }, y: Record) { + x = y; + y = x; // Error + ~ +!!! error TS2322: Type '{ [key: string]: T; }' is not assignable to type 'Record'. + } + + function f2(x: { [key: string]: T }, y: Record) { + x = y; + y = x; + } + + function f3(x: { [key: string]: T }, y: Record) { + x = y; // Error + ~ +!!! error TS2322: Type 'Record' is not assignable to type '{ [key: string]: T; }'. +!!! error TS2322: Type 'U' is not assignable to type 'T'. + y = x; // Error + ~ +!!! error TS2322: Type '{ [key: string]: T; }' is not assignable to type 'Record'. + } + + // Repro from #14548 + + type Dictionary = { + [key: string]: string; + }; + + interface IBaseEntity { + name: string; + properties: Dictionary; + } + + interface IEntity extends IBaseEntity { + properties: Record; + } + \ No newline at end of file diff --git a/tests/baselines/reference/indexSignatureAndMappedType.js b/tests/baselines/reference/indexSignatureAndMappedType.js new file mode 100644 index 00000000000..c35da4f4931 --- /dev/null +++ b/tests/baselines/reference/indexSignatureAndMappedType.js @@ -0,0 +1,73 @@ +//// [indexSignatureAndMappedType.ts] +// A mapped type { [P in K]: X }, where K is a generic type, is related to +// { [key: string]: Y } if X is related to Y. + +function f1(x: { [key: string]: T }, y: Record) { + x = y; + y = x; // Error +} + +function f2(x: { [key: string]: T }, y: Record) { + x = y; + y = x; +} + +function f3(x: { [key: string]: T }, y: Record) { + x = y; // Error + y = x; // Error +} + +// Repro from #14548 + +type Dictionary = { + [key: string]: string; +}; + +interface IBaseEntity { + name: string; + properties: Dictionary; +} + +interface IEntity extends IBaseEntity { + properties: Record; +} + + +//// [indexSignatureAndMappedType.js] +"use strict"; +// A mapped type { [P in K]: X }, where K is a generic type, is related to +// { [key: string]: Y } if X is related to Y. +function f1(x, y) { + x = y; + y = x; // Error +} +function f2(x, y) { + x = y; + y = x; +} +function f3(x, y) { + x = y; // Error + y = x; // Error +} + + +//// [indexSignatureAndMappedType.d.ts] +declare function f1(x: { + [key: string]: T; +}, y: Record): void; +declare function f2(x: { + [key: string]: T; +}, y: Record): void; +declare function f3(x: { + [key: string]: T; +}, y: Record): void; +declare type Dictionary = { + [key: string]: string; +}; +interface IBaseEntity { + name: string; + properties: Dictionary; +} +interface IEntity extends IBaseEntity { + properties: Record; +} diff --git a/tests/cases/compiler/indexSignatureAndMappedType.ts b/tests/cases/compiler/indexSignatureAndMappedType.ts new file mode 100644 index 00000000000..1070472a241 --- /dev/null +++ b/tests/cases/compiler/indexSignatureAndMappedType.ts @@ -0,0 +1,35 @@ +// @strict: true +// @declaration: true + +// A mapped type { [P in K]: X }, where K is a generic type, is related to +// { [key: string]: Y } if X is related to Y. + +function f1(x: { [key: string]: T }, y: Record) { + x = y; + y = x; // Error +} + +function f2(x: { [key: string]: T }, y: Record) { + x = y; + y = x; +} + +function f3(x: { [key: string]: T }, y: Record) { + x = y; // Error + y = x; // Error +} + +// Repro from #14548 + +type Dictionary = { + [key: string]: string; +}; + +interface IBaseEntity { + name: string; + properties: Dictionary; +} + +interface IEntity extends IBaseEntity { + properties: Record; +} From 3efeb1e27f60a95dad66c148295bfa5a65f56146 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 7 Aug 2017 13:59:52 -0700 Subject: [PATCH 3/3] Address CR feedback --- .../reference/indexSignatureAndMappedType.errors.txt | 2 +- tests/baselines/reference/indexSignatureAndMappedType.js | 4 ++-- tests/cases/compiler/indexSignatureAndMappedType.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/indexSignatureAndMappedType.errors.txt b/tests/baselines/reference/indexSignatureAndMappedType.errors.txt index c8ae0494015..623fcd11bd0 100644 --- a/tests/baselines/reference/indexSignatureAndMappedType.errors.txt +++ b/tests/baselines/reference/indexSignatureAndMappedType.errors.txt @@ -15,7 +15,7 @@ tests/cases/compiler/indexSignatureAndMappedType.ts(16,5): error TS2322: Type '{ !!! error TS2322: Type '{ [key: string]: T; }' is not assignable to type 'Record'. } - function f2(x: { [key: string]: T }, y: Record) { + function f2(x: { [key: string]: T }, y: Record) { x = y; y = x; } diff --git a/tests/baselines/reference/indexSignatureAndMappedType.js b/tests/baselines/reference/indexSignatureAndMappedType.js index c35da4f4931..be58286fb46 100644 --- a/tests/baselines/reference/indexSignatureAndMappedType.js +++ b/tests/baselines/reference/indexSignatureAndMappedType.js @@ -7,7 +7,7 @@ function f1(x: { [key: string]: T }, y: Record) { y = x; // Error } -function f2(x: { [key: string]: T }, y: Record) { +function f2(x: { [key: string]: T }, y: Record) { x = y; y = x; } @@ -55,7 +55,7 @@ function f3(x, y) { declare function f1(x: { [key: string]: T; }, y: Record): void; -declare function f2(x: { +declare function f2(x: { [key: string]: T; }, y: Record): void; declare function f3(x: { diff --git a/tests/cases/compiler/indexSignatureAndMappedType.ts b/tests/cases/compiler/indexSignatureAndMappedType.ts index 1070472a241..b5f9e8a0030 100644 --- a/tests/cases/compiler/indexSignatureAndMappedType.ts +++ b/tests/cases/compiler/indexSignatureAndMappedType.ts @@ -9,7 +9,7 @@ function f1(x: { [key: string]: T }, y: Record) { y = x; // Error } -function f2(x: { [key: string]: T }, y: Record) { +function f2(x: { [key: string]: T }, y: Record) { x = y; y = x; }