diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 898ebbfbcd6ad..d1c0655e37a79 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12785,9 +12785,10 @@ namespace ts { (template).indexType === getTypeParameterFromMappedType(target)) { return Ternary.True; } + if (!isGenericMappedType(source)) { const targetConstraint = getConstraintTypeFromMappedType(target); - const sourceKeys = getIndexType(source); + const sourceKeys = filterType(getIndexType(source), t => !(t.flags & (TypeFlags.String | TypeFlags.Number))); const hasOptionalUnionKeys = modifiers & MappedTypeModifiers.IncludeOptional && targetConstraint.flags & TypeFlags.Union; const filteredByApplicability = hasOptionalUnionKeys ? filterType(targetConstraint, t => !!isRelatedTo(t, sourceKeys)) : undefined; // A source type T is related to a target type { [P in Q]: X } if Q is related to keyof T and T[Q] is related to X. diff --git a/tests/baselines/reference/indexSignatureAndMappedType.errors.txt b/tests/baselines/reference/indexSignatureAndMappedType.errors.txt index 623fcd11bd050..9c1982eb49c69 100644 --- a/tests/baselines/reference/indexSignatureAndMappedType.errors.txt +++ b/tests/baselines/reference/indexSignatureAndMappedType.errors.txt @@ -2,9 +2,11 @@ tests/cases/compiler/indexSignatureAndMappedType.ts(6,5): error TS2322: Type '{ 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(37,5): error TS2322: Type '{ [x: string]: number; }' is not assignable to type 'Record'. +tests/cases/compiler/indexSignatureAndMappedType.ts(42,5): error TS2741: Property 'a' is missing in type '{ [x: string]: number; }' but required in type 'Record<"a", number>'. -==== tests/cases/compiler/indexSignatureAndMappedType.ts (3 errors) ==== +==== tests/cases/compiler/indexSignatureAndMappedType.ts (5 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. @@ -44,4 +46,20 @@ tests/cases/compiler/indexSignatureAndMappedType.ts(16,5): error TS2322: Type '{ interface IEntity extends IBaseEntity { properties: Record; } + + // Repro from #28798 + + function constrainedRecord(x: Record, y: { [x: string]: number }) { + x = y; // error + ~ +!!! error TS2322: Type '{ [x: string]: number; }' is not assignable to type 'Record'. + y = x; + } + + function concreteRecord(x: Record<'a', number>, y: { [x: string]: number }) { + x = y; // error + ~ +!!! error TS2741: Property 'a' is missing in type '{ [x: string]: number; }' but required in type 'Record<"a", number>'. + y = x; + } \ No newline at end of file diff --git a/tests/baselines/reference/indexSignatureAndMappedType.js b/tests/baselines/reference/indexSignatureAndMappedType.js index be58286fb46cc..d7bb2a448edaa 100644 --- a/tests/baselines/reference/indexSignatureAndMappedType.js +++ b/tests/baselines/reference/indexSignatureAndMappedType.js @@ -31,6 +31,18 @@ interface IBaseEntity { interface IEntity extends IBaseEntity { properties: Record; } + +// Repro from #28798 + +function constrainedRecord(x: Record, y: { [x: string]: number }) { + x = y; // error + y = x; +} + +function concreteRecord(x: Record<'a', number>, y: { [x: string]: number }) { + x = y; // error + y = x; +} //// [indexSignatureAndMappedType.js] @@ -49,6 +61,15 @@ function f3(x, y) { x = y; // Error y = x; // Error } +// Repro from #28798 +function constrainedRecord(x, y) { + x = y; // error + y = x; +} +function concreteRecord(x, y) { + x = y; // error + y = x; +} //// [indexSignatureAndMappedType.d.ts] @@ -71,3 +92,9 @@ interface IBaseEntity { interface IEntity extends IBaseEntity { properties: Record; } +declare function constrainedRecord(x: Record, y: { + [x: string]: number; +}): void; +declare function concreteRecord(x: Record<'a', number>, y: { + [x: string]: number; +}): void; diff --git a/tests/baselines/reference/indexSignatureAndMappedType.symbols b/tests/baselines/reference/indexSignatureAndMappedType.symbols index 0e33d65ee4028..2a1bb32925368 100644 --- a/tests/baselines/reference/indexSignatureAndMappedType.symbols +++ b/tests/baselines/reference/indexSignatureAndMappedType.symbols @@ -96,3 +96,39 @@ interface IEntity extends IBaseEntity { >T : Symbol(T, Decl(indexSignatureAndMappedType.ts, 29, 18)) } +// Repro from #28798 + +function constrainedRecord(x: Record, y: { [x: string]: number }) { +>constrainedRecord : Symbol(constrainedRecord, Decl(indexSignatureAndMappedType.ts, 31, 1)) +>K : Symbol(K, Decl(indexSignatureAndMappedType.ts, 35, 27)) +>x : Symbol(x, Decl(indexSignatureAndMappedType.ts, 35, 42)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(indexSignatureAndMappedType.ts, 35, 27)) +>y : Symbol(y, Decl(indexSignatureAndMappedType.ts, 35, 63)) +>x : Symbol(x, Decl(indexSignatureAndMappedType.ts, 35, 70)) + + x = y; // error +>x : Symbol(x, Decl(indexSignatureAndMappedType.ts, 35, 42)) +>y : Symbol(y, Decl(indexSignatureAndMappedType.ts, 35, 63)) + + y = x; +>y : Symbol(y, Decl(indexSignatureAndMappedType.ts, 35, 63)) +>x : Symbol(x, Decl(indexSignatureAndMappedType.ts, 35, 42)) +} + +function concreteRecord(x: Record<'a', number>, y: { [x: string]: number }) { +>concreteRecord : Symbol(concreteRecord, Decl(indexSignatureAndMappedType.ts, 38, 1)) +>x : Symbol(x, Decl(indexSignatureAndMappedType.ts, 40, 24)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>y : Symbol(y, Decl(indexSignatureAndMappedType.ts, 40, 47)) +>x : Symbol(x, Decl(indexSignatureAndMappedType.ts, 40, 54)) + + x = y; // error +>x : Symbol(x, Decl(indexSignatureAndMappedType.ts, 40, 24)) +>y : Symbol(y, Decl(indexSignatureAndMappedType.ts, 40, 47)) + + y = x; +>y : Symbol(y, Decl(indexSignatureAndMappedType.ts, 40, 47)) +>x : Symbol(x, Decl(indexSignatureAndMappedType.ts, 40, 24)) +} + diff --git a/tests/baselines/reference/indexSignatureAndMappedType.types b/tests/baselines/reference/indexSignatureAndMappedType.types index 9f3b3e3fe6cc5..cdc675f668c70 100644 --- a/tests/baselines/reference/indexSignatureAndMappedType.types +++ b/tests/baselines/reference/indexSignatureAndMappedType.types @@ -76,3 +76,39 @@ interface IEntity extends IBaseEntity { >properties : Record } +// Repro from #28798 + +function constrainedRecord(x: Record, y: { [x: string]: number }) { +>constrainedRecord : (x: Record, y: { [x: string]: number; }) => void +>x : Record +>y : { [x: string]: number; } +>x : string + + x = y; // error +>x = y : { [x: string]: number; } +>x : Record +>y : { [x: string]: number; } + + y = x; +>y = x : Record +>y : { [x: string]: number; } +>x : Record +} + +function concreteRecord(x: Record<'a', number>, y: { [x: string]: number }) { +>concreteRecord : (x: Record<"a", number>, y: { [x: string]: number; }) => void +>x : Record<"a", number> +>y : { [x: string]: number; } +>x : string + + x = y; // error +>x = y : { [x: string]: number; } +>x : Record<"a", number> +>y : { [x: string]: number; } + + y = x; +>y = x : Record<"a", number> +>y : { [x: string]: number; } +>x : Record<"a", number> +} + diff --git a/tests/cases/compiler/indexSignatureAndMappedType.ts b/tests/cases/compiler/indexSignatureAndMappedType.ts index b5f9e8a0030ac..0dd665918ad5b 100644 --- a/tests/cases/compiler/indexSignatureAndMappedType.ts +++ b/tests/cases/compiler/indexSignatureAndMappedType.ts @@ -33,3 +33,15 @@ interface IBaseEntity { interface IEntity extends IBaseEntity { properties: Record; } + +// Repro from #28798 + +function constrainedRecord(x: Record, y: { [x: string]: number }) { + x = y; // error + y = x; +} + +function concreteRecord(x: Record<'a', number>, y: { [x: string]: number }) { + x = y; // error + y = x; +}