From ee30b436eb4c4ffc72ae1394653140dcb2583899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 29 Dec 2024 13:57:20 +0100 Subject: [PATCH] Fixed an issue with excess/ common property check errors being incorrectly reported when relating to targets with multiple index signatures --- src/compiler/checker.ts | 19 +- ...eckWithMultipleIndexSignatures1.errors.txt | 57 ++++++ ...yCheckWithMultipleIndexSignatures1.symbols | 115 +++++++++++ ...rtyCheckWithMultipleIndexSignatures1.types | 167 ++++++++++++++++ ...eckWithMultipleIndexSignatures1.errors.txt | 59 ++++++ ...yCheckWithMultipleIndexSignatures1.symbols | 121 ++++++++++++ ...rtyCheckWithMultipleIndexSignatures1.types | 185 ++++++++++++++++++ ...opertyCheckWithMultipleIndexSignatures1.ts | 48 +++++ ...opertyCheckWithMultipleIndexSignatures1.ts | 50 +++++ 9 files changed, 812 insertions(+), 9 deletions(-) create mode 100644 tests/baselines/reference/commonPropertyCheckWithMultipleIndexSignatures1.errors.txt create mode 100644 tests/baselines/reference/commonPropertyCheckWithMultipleIndexSignatures1.symbols create mode 100644 tests/baselines/reference/commonPropertyCheckWithMultipleIndexSignatures1.types create mode 100644 tests/baselines/reference/excessPropertyCheckWithMultipleIndexSignatures1.errors.txt create mode 100644 tests/baselines/reference/excessPropertyCheckWithMultipleIndexSignatures1.symbols create mode 100644 tests/baselines/reference/excessPropertyCheckWithMultipleIndexSignatures1.types create mode 100644 tests/cases/compiler/commonPropertyCheckWithMultipleIndexSignatures1.ts create mode 100644 tests/cases/compiler/excessPropertyCheckWithMultipleIndexSignatures1.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 80b61edd3657a..083ee8af61432 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22130,7 +22130,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * * Ternary.Maybe if they are related with assumptions of other relationships, or * * Ternary.False if they are not related. */ - function isRelatedTo(originalSource: Type, originalTarget: Type, recursionFlags: RecursionFlags = RecursionFlags.Both, reportErrors = false, headMessage?: DiagnosticMessage, intersectionState = IntersectionState.None): Ternary { + function isRelatedTo(originalSource: Type, originalTarget: Type, recursionFlags: RecursionFlags = RecursionFlags.Both, reportErrors = false, headMessage?: DiagnosticMessage, intersectionState = IntersectionState.None, allowExtraPropertyChecks = true): Ternary { if (originalSource === originalTarget) return Ternary.True; // Before normalization: if `source` is type an object type, and `target` is primitive, @@ -22192,7 +22192,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ) return Ternary.True; if (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable) { - const isPerformingExcessPropertyChecks = !(intersectionState & IntersectionState.Target) && (isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral); + const isPerformingExcessPropertyChecks = allowExtraPropertyChecks && !(intersectionState & IntersectionState.Target) && (isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral); if (isPerformingExcessPropertyChecks) { if (hasExcessProperties(source as FreshObjectLiteralType, target, reportErrors)) { if (reportErrors) { @@ -22202,7 +22202,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - const isPerformingCommonPropertyChecks = (relation !== comparableRelation || isUnitType(source)) && + const isPerformingCommonPropertyChecks = allowExtraPropertyChecks && (relation !== comparableRelation || isUnitType(source)) && !(intersectionState & IntersectionState.Target) && source.flags & (TypeFlags.Primitive | TypeFlags.Object | TypeFlags.Intersection) && source !== globalObjectType && target.flags & (TypeFlags.Object | TypeFlags.Intersection) && isWeakType(target) && @@ -24113,7 +24113,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function membersRelatedToIndexInfo(source: Type, targetInfo: IndexInfo, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function membersRelatedToIndexInfo(source: Type, target: Type, targetInfo: IndexInfo, reportErrors: boolean, intersectionState: IntersectionState): Ternary { let result = Ternary.True; const keyType = targetInfo.keyType; const props = source.flags & TypeFlags.Intersection ? getPropertiesOfUnionOrIntersectionType(source as IntersectionType) : getPropertiesOfObjectType(source); @@ -24122,12 +24122,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isIgnoredJsxProperty(source, prop)) { continue; } - if (isApplicableIndexType(getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique), keyType)) { + const propKeyType = getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique); + if (isApplicableIndexType(propKeyType, keyType)) { const propType = getNonMissingTypeOfSymbol(prop); const type = exactOptionalPropertyTypes || propType.flags & TypeFlags.Undefined || keyType === numberType || !(prop.flags & SymbolFlags.Optional) ? propType : getTypeWithFacts(propType, TypeFacts.NEUndefined); - const related = isRelatedTo(type, targetInfo.type, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + const related = isRelatedTo(type, targetInfo.type, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState, targetInfo === getApplicableIndexInfo(target, propKeyType)); if (!related) { if (reportErrors) { reportError(Diagnostics.Property_0_is_incompatible_with_index_signature, symbolToString(prop)); @@ -24172,7 +24173,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const targetInfo of indexInfos) { const related = relation !== strictSubtypeRelation && !sourceIsPrimitive && targetHasStringIndex && targetInfo.type.flags & TypeFlags.Any ? Ternary.True : isGenericMappedType(source) && targetHasStringIndex ? isRelatedTo(getTemplateTypeFromMappedType(source), targetInfo.type, RecursionFlags.Both, reportErrors) : - typeRelatedToIndexInfo(source, targetInfo, reportErrors, intersectionState); + typeRelatedToIndexInfo(source, target, targetInfo, reportErrors, intersectionState); if (!related) { return Ternary.False; } @@ -24181,7 +24182,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function typeRelatedToIndexInfo(source: Type, targetInfo: IndexInfo, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function typeRelatedToIndexInfo(source: Type, target: Type, targetInfo: IndexInfo, reportErrors: boolean, intersectionState: IntersectionState): Ternary { const sourceInfo = getApplicableIndexInfo(source, targetInfo.keyType); if (sourceInfo) { return indexInfoRelatedTo(sourceInfo, targetInfo, reportErrors, intersectionState); @@ -24190,7 +24191,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // only fresh object literals are considered to have inferred index signatures. This ensures { [x: string]: xxx } <: {} but // not vice-versa. Without this rule, those types would be mutual strict subtypes. if (!(intersectionState & IntersectionState.Source) && (relation !== strictSubtypeRelation || getObjectFlags(source) & ObjectFlags.FreshLiteral) && isObjectTypeWithInferableIndex(source)) { - return membersRelatedToIndexInfo(source, targetInfo, reportErrors, intersectionState); + return membersRelatedToIndexInfo(source, target, targetInfo, reportErrors, intersectionState); } if (reportErrors) { reportError(Diagnostics.Index_signature_for_type_0_is_missing_in_type_1, typeToString(targetInfo.keyType), typeToString(source)); diff --git a/tests/baselines/reference/commonPropertyCheckWithMultipleIndexSignatures1.errors.txt b/tests/baselines/reference/commonPropertyCheckWithMultipleIndexSignatures1.errors.txt new file mode 100644 index 0000000000000..d43b0d8ba3b46 --- /dev/null +++ b/tests/baselines/reference/commonPropertyCheckWithMultipleIndexSignatures1.errors.txt @@ -0,0 +1,57 @@ +commonPropertyCheckWithMultipleIndexSignatures1.ts(21,8): error TS2353: Object literal may only specify known properties, and 'notCommon' does not exist in type 'ISubType'. +commonPropertyCheckWithMultipleIndexSignatures1.ts(44,12): error TS2353: Object literal may only specify known properties, and 'notCommon' does not exist in type 'ISubType_2'. + + +==== commonPropertyCheckWithMultipleIndexSignatures1.ts (2 errors) ==== + interface ITopType { + tKey?: string; + } + + interface ISubType extends ITopType { + sKey?: string; + } + + interface ITestInteface { + [pA: string]: ITopType; + [pB: number]: ISubType; + } + + const testObj1: ITestInteface = { + a: { tKey: "tVal" }, + 1: { tKey: "tVal", sKey: "sVal" }, + }; + + const testObj1_2: ITestInteface = { + a: { tKey: "tVal" }, + 1: { notCommon: "val3" }, + ~~~~~~~~~ +!!! error TS2353: Object literal may only specify known properties, and 'notCommon' does not exist in type 'ISubType'. +!!! related TS6501 commonPropertyCheckWithMultipleIndexSignatures1.ts:11:3: The expected type comes from this index signature. + }; + + interface ITopType_2 { + tKey_2?: string; + } + + interface ISubType_2 extends ITopType_2 { + sKey_2?: string; + } + + interface ITestInteface_2 { + [pA_2: string]: ITopType_2; + [pB_2: `sub_${string}`]: ISubType_2; + } + + const testObj2: ITestInteface_2 = { + a: { tKey_2: "tVal_2 " }, + sub_b: { tKey_2: "tVal_2 ", sKey_2: "sVal_2" }, + }; + + const testObj2_2: ITestInteface_2 = { + a: { tKey_2: "tVal_2 " }, + sub_b: { notCommon: "val3" }, + ~~~~~~~~~ +!!! error TS2353: Object literal may only specify known properties, and 'notCommon' does not exist in type 'ISubType_2'. +!!! related TS6501 commonPropertyCheckWithMultipleIndexSignatures1.ts:34:3: The expected type comes from this index signature. + }; + \ No newline at end of file diff --git a/tests/baselines/reference/commonPropertyCheckWithMultipleIndexSignatures1.symbols b/tests/baselines/reference/commonPropertyCheckWithMultipleIndexSignatures1.symbols new file mode 100644 index 0000000000000..d772dcc75b871 --- /dev/null +++ b/tests/baselines/reference/commonPropertyCheckWithMultipleIndexSignatures1.symbols @@ -0,0 +1,115 @@ +//// [tests/cases/compiler/commonPropertyCheckWithMultipleIndexSignatures1.ts] //// + +=== commonPropertyCheckWithMultipleIndexSignatures1.ts === +interface ITopType { +>ITopType : Symbol(ITopType, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 0, 0)) + + tKey?: string; +>tKey : Symbol(ITopType.tKey, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 0, 20)) +} + +interface ISubType extends ITopType { +>ISubType : Symbol(ISubType, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 2, 1)) +>ITopType : Symbol(ITopType, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 0, 0)) + + sKey?: string; +>sKey : Symbol(ISubType.sKey, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 4, 37)) +} + +interface ITestInteface { +>ITestInteface : Symbol(ITestInteface, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 6, 1)) + + [pA: string]: ITopType; +>pA : Symbol(pA, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 9, 3)) +>ITopType : Symbol(ITopType, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 0, 0)) + + [pB: number]: ISubType; +>pB : Symbol(pB, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 10, 3)) +>ISubType : Symbol(ISubType, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 2, 1)) +} + +const testObj1: ITestInteface = { +>testObj1 : Symbol(testObj1, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 13, 5)) +>ITestInteface : Symbol(ITestInteface, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 6, 1)) + + a: { tKey: "tVal" }, +>a : Symbol(a, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 13, 33)) +>tKey : Symbol(tKey, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 14, 6)) + + 1: { tKey: "tVal", sKey: "sVal" }, +>1 : Symbol(1, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 14, 22)) +>tKey : Symbol(tKey, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 15, 6)) +>sKey : Symbol(sKey, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 15, 20)) + +}; + +const testObj1_2: ITestInteface = { +>testObj1_2 : Symbol(testObj1_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 18, 5)) +>ITestInteface : Symbol(ITestInteface, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 6, 1)) + + a: { tKey: "tVal" }, +>a : Symbol(a, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 18, 35)) +>tKey : Symbol(tKey, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 19, 6)) + + 1: { notCommon: "val3" }, +>1 : Symbol(1, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 19, 22)) +>notCommon : Symbol(notCommon, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 20, 6)) + +}; + +interface ITopType_2 { +>ITopType_2 : Symbol(ITopType_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 21, 2)) + + tKey_2?: string; +>tKey_2 : Symbol(ITopType_2.tKey_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 23, 22)) +} + +interface ISubType_2 extends ITopType_2 { +>ISubType_2 : Symbol(ISubType_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 25, 1)) +>ITopType_2 : Symbol(ITopType_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 21, 2)) + + sKey_2?: string; +>sKey_2 : Symbol(ISubType_2.sKey_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 27, 41)) +} + +interface ITestInteface_2 { +>ITestInteface_2 : Symbol(ITestInteface_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 29, 1)) + + [pA_2: string]: ITopType_2; +>pA_2 : Symbol(pA_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 32, 3)) +>ITopType_2 : Symbol(ITopType_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 21, 2)) + + [pB_2: `sub_${string}`]: ISubType_2; +>pB_2 : Symbol(pB_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 33, 3)) +>ISubType_2 : Symbol(ISubType_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 25, 1)) +} + +const testObj2: ITestInteface_2 = { +>testObj2 : Symbol(testObj2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 36, 5)) +>ITestInteface_2 : Symbol(ITestInteface_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 29, 1)) + + a: { tKey_2: "tVal_2 " }, +>a : Symbol(a, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 36, 35)) +>tKey_2 : Symbol(tKey_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 37, 6)) + + sub_b: { tKey_2: "tVal_2 ", sKey_2: "sVal_2" }, +>sub_b : Symbol(sub_b, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 37, 27)) +>tKey_2 : Symbol(tKey_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 38, 10)) +>sKey_2 : Symbol(sKey_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 38, 29)) + +}; + +const testObj2_2: ITestInteface_2 = { +>testObj2_2 : Symbol(testObj2_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 41, 5)) +>ITestInteface_2 : Symbol(ITestInteface_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 29, 1)) + + a: { tKey_2: "tVal_2 " }, +>a : Symbol(a, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 41, 37)) +>tKey_2 : Symbol(tKey_2, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 42, 6)) + + sub_b: { notCommon: "val3" }, +>sub_b : Symbol(sub_b, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 42, 27)) +>notCommon : Symbol(notCommon, Decl(commonPropertyCheckWithMultipleIndexSignatures1.ts, 43, 10)) + +}; + diff --git a/tests/baselines/reference/commonPropertyCheckWithMultipleIndexSignatures1.types b/tests/baselines/reference/commonPropertyCheckWithMultipleIndexSignatures1.types new file mode 100644 index 0000000000000..3bf7b13accadd --- /dev/null +++ b/tests/baselines/reference/commonPropertyCheckWithMultipleIndexSignatures1.types @@ -0,0 +1,167 @@ +//// [tests/cases/compiler/commonPropertyCheckWithMultipleIndexSignatures1.ts] //// + +=== commonPropertyCheckWithMultipleIndexSignatures1.ts === +interface ITopType { + tKey?: string; +>tKey : string | undefined +> : ^^^^^^^^^^^^^^^^^^ +} + +interface ISubType extends ITopType { + sKey?: string; +>sKey : string | undefined +> : ^^^^^^^^^^^^^^^^^^ +} + +interface ITestInteface { + [pA: string]: ITopType; +>pA : string +> : ^^^^^^ + + [pB: number]: ISubType; +>pB : number +> : ^^^^^^ +} + +const testObj1: ITestInteface = { +>testObj1 : ITestInteface +> : ^^^^^^^^^^^^^ +>{ a: { tKey: "tVal" }, 1: { tKey: "tVal", sKey: "sVal" },} : { a: { tKey: string; }; 1: { tKey: string; sKey: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + a: { tKey: "tVal" }, +>a : { tKey: string; } +> : ^^^^^^^^^^^^^^^^^ +>{ tKey: "tVal" } : { tKey: string; } +> : ^^^^^^^^^^^^^^^^^ +>tKey : string +> : ^^^^^^ +>"tVal" : "tVal" +> : ^^^^^^ + + 1: { tKey: "tVal", sKey: "sVal" }, +>1 : { tKey: string; sKey: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ tKey: "tVal", sKey: "sVal" } : { tKey: string; sKey: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>tKey : string +> : ^^^^^^ +>"tVal" : "tVal" +> : ^^^^^^ +>sKey : string +> : ^^^^^^ +>"sVal" : "sVal" +> : ^^^^^^ + +}; + +const testObj1_2: ITestInteface = { +>testObj1_2 : ITestInteface +> : ^^^^^^^^^^^^^ +>{ a: { tKey: "tVal" }, 1: { notCommon: "val3" },} : { a: { tKey: string; }; 1: { notCommon: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + a: { tKey: "tVal" }, +>a : { tKey: string; } +> : ^^^^^^^^^^^^^^^^^ +>{ tKey: "tVal" } : { tKey: string; } +> : ^^^^^^^^^^^^^^^^^ +>tKey : string +> : ^^^^^^ +>"tVal" : "tVal" +> : ^^^^^^ + + 1: { notCommon: "val3" }, +>1 : { notCommon: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^ +>{ notCommon: "val3" } : { notCommon: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^ +>notCommon : string +> : ^^^^^^ +>"val3" : "val3" +> : ^^^^^^ + +}; + +interface ITopType_2 { + tKey_2?: string; +>tKey_2 : string | undefined +> : ^^^^^^^^^^^^^^^^^^ +} + +interface ISubType_2 extends ITopType_2 { + sKey_2?: string; +>sKey_2 : string | undefined +> : ^^^^^^^^^^^^^^^^^^ +} + +interface ITestInteface_2 { + [pA_2: string]: ITopType_2; +>pA_2 : string +> : ^^^^^^ + + [pB_2: `sub_${string}`]: ISubType_2; +>pB_2 : `sub_${string}` +> : ^^^^^^^^^^^^^^^ +} + +const testObj2: ITestInteface_2 = { +>testObj2 : ITestInteface_2 +> : ^^^^^^^^^^^^^^^ +>{ a: { tKey_2: "tVal_2 " }, sub_b: { tKey_2: "tVal_2 ", sKey_2: "sVal_2" },} : { a: { tKey_2: string; }; sub_b: { tKey_2: string; sKey_2: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + a: { tKey_2: "tVal_2 " }, +>a : { tKey_2: string; } +> : ^^^^^^^^^^^^^^^^^^^ +>{ tKey_2: "tVal_2 " } : { tKey_2: string; } +> : ^^^^^^^^^^^^^^^^^^^ +>tKey_2 : string +> : ^^^^^^ +>"tVal_2 " : "tVal_2 " +> : ^^^^^^^^^ + + sub_b: { tKey_2: "tVal_2 ", sKey_2: "sVal_2" }, +>sub_b : { tKey_2: string; sKey_2: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ tKey_2: "tVal_2 ", sKey_2: "sVal_2" } : { tKey_2: string; sKey_2: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>tKey_2 : string +> : ^^^^^^ +>"tVal_2 " : "tVal_2 " +> : ^^^^^^^^^ +>sKey_2 : string +> : ^^^^^^ +>"sVal_2" : "sVal_2" +> : ^^^^^^^^ + +}; + +const testObj2_2: ITestInteface_2 = { +>testObj2_2 : ITestInteface_2 +> : ^^^^^^^^^^^^^^^ +>{ a: { tKey_2: "tVal_2 " }, sub_b: { notCommon: "val3" },} : { a: { tKey_2: string; }; sub_b: { notCommon: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + a: { tKey_2: "tVal_2 " }, +>a : { tKey_2: string; } +> : ^^^^^^^^^^^^^^^^^^^ +>{ tKey_2: "tVal_2 " } : { tKey_2: string; } +> : ^^^^^^^^^^^^^^^^^^^ +>tKey_2 : string +> : ^^^^^^ +>"tVal_2 " : "tVal_2 " +> : ^^^^^^^^^ + + sub_b: { notCommon: "val3" }, +>sub_b : { notCommon: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^ +>{ notCommon: "val3" } : { notCommon: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^ +>notCommon : string +> : ^^^^^^ +>"val3" : "val3" +> : ^^^^^^ + +}; + diff --git a/tests/baselines/reference/excessPropertyCheckWithMultipleIndexSignatures1.errors.txt b/tests/baselines/reference/excessPropertyCheckWithMultipleIndexSignatures1.errors.txt new file mode 100644 index 0000000000000..f8c7e98b9d706 --- /dev/null +++ b/tests/baselines/reference/excessPropertyCheckWithMultipleIndexSignatures1.errors.txt @@ -0,0 +1,59 @@ +excessPropertyCheckWithMultipleIndexSignatures1.ts(23,36): error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type 'ISubType'. +excessPropertyCheckWithMultipleIndexSignatures1.ts(46,49): error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type 'ISubType_2'. + + +==== excessPropertyCheckWithMultipleIndexSignatures1.ts (2 errors) ==== + // https://github.com/microsoft/TypeScript/issues/58442 + + interface ITopType { + tKey: string; + } + + interface ISubType extends ITopType { + sKey: string; + } + + interface ITestInteface { + [pA: string]: ITopType; + [pB: number]: ISubType; + } + + const testObj1: ITestInteface = { + a: { tKey: "tVal" }, + 1: { tKey: "tVal", sKey: "sVal" }, + }; + + const testObj1_2: ITestInteface = { + a: { tKey: "tVal" }, + 1: { tKey: "tVal", sKey: "sVal", extra: "val3" }, + ~~~~~ +!!! error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type 'ISubType'. +!!! related TS6501 excessPropertyCheckWithMultipleIndexSignatures1.ts:13:3: The expected type comes from this index signature. + }; + + interface ITopType_2 { + tKey_2: string; + } + + interface ISubType_2 extends ITopType_2 { + sKey_2: string; + } + + interface ITestInteface_2 { + [pA_2: string]: ITopType_2; + [pB_2: `sub_${string}`]: ISubType_2; + } + + const testObj2: ITestInteface_2 = { + a: { tKey_2: "tVal_2 " }, + sub_b: { tKey_2: "tVal_2 ", sKey_2: "sVal_2" }, + }; + + const testObj2_2: ITestInteface_2 = { + a: { tKey_2: "tVal_2 " }, + sub_b: { tKey_2: "tVal_2 ", sKey_2: "sVal_2", extra: "val3" }, + ~~~~~ +!!! error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type 'ISubType_2'. +!!! related TS6501 excessPropertyCheckWithMultipleIndexSignatures1.ts:36:3: The expected type comes from this index signature. + }; + \ No newline at end of file diff --git a/tests/baselines/reference/excessPropertyCheckWithMultipleIndexSignatures1.symbols b/tests/baselines/reference/excessPropertyCheckWithMultipleIndexSignatures1.symbols new file mode 100644 index 0000000000000..bacdeb75aafe8 --- /dev/null +++ b/tests/baselines/reference/excessPropertyCheckWithMultipleIndexSignatures1.symbols @@ -0,0 +1,121 @@ +//// [tests/cases/compiler/excessPropertyCheckWithMultipleIndexSignatures1.ts] //// + +=== excessPropertyCheckWithMultipleIndexSignatures1.ts === +// https://github.com/microsoft/TypeScript/issues/58442 + +interface ITopType { +>ITopType : Symbol(ITopType, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 0, 0)) + + tKey: string; +>tKey : Symbol(ITopType.tKey, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 2, 20)) +} + +interface ISubType extends ITopType { +>ISubType : Symbol(ISubType, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 4, 1)) +>ITopType : Symbol(ITopType, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 0, 0)) + + sKey: string; +>sKey : Symbol(ISubType.sKey, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 6, 37)) +} + +interface ITestInteface { +>ITestInteface : Symbol(ITestInteface, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 8, 1)) + + [pA: string]: ITopType; +>pA : Symbol(pA, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 11, 3)) +>ITopType : Symbol(ITopType, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 0, 0)) + + [pB: number]: ISubType; +>pB : Symbol(pB, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 12, 3)) +>ISubType : Symbol(ISubType, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 4, 1)) +} + +const testObj1: ITestInteface = { +>testObj1 : Symbol(testObj1, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 15, 5)) +>ITestInteface : Symbol(ITestInteface, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 8, 1)) + + a: { tKey: "tVal" }, +>a : Symbol(a, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 15, 33)) +>tKey : Symbol(tKey, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 16, 6)) + + 1: { tKey: "tVal", sKey: "sVal" }, +>1 : Symbol(1, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 16, 22)) +>tKey : Symbol(tKey, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 17, 6)) +>sKey : Symbol(sKey, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 17, 20)) + +}; + +const testObj1_2: ITestInteface = { +>testObj1_2 : Symbol(testObj1_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 20, 5)) +>ITestInteface : Symbol(ITestInteface, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 8, 1)) + + a: { tKey: "tVal" }, +>a : Symbol(a, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 20, 35)) +>tKey : Symbol(tKey, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 21, 6)) + + 1: { tKey: "tVal", sKey: "sVal", extra: "val3" }, +>1 : Symbol(1, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 21, 22)) +>tKey : Symbol(tKey, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 22, 6)) +>sKey : Symbol(sKey, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 22, 20)) +>extra : Symbol(extra, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 22, 34)) + +}; + +interface ITopType_2 { +>ITopType_2 : Symbol(ITopType_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 23, 2)) + + tKey_2: string; +>tKey_2 : Symbol(ITopType_2.tKey_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 25, 22)) +} + +interface ISubType_2 extends ITopType_2 { +>ISubType_2 : Symbol(ISubType_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 27, 1)) +>ITopType_2 : Symbol(ITopType_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 23, 2)) + + sKey_2: string; +>sKey_2 : Symbol(ISubType_2.sKey_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 29, 41)) +} + +interface ITestInteface_2 { +>ITestInteface_2 : Symbol(ITestInteface_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 31, 1)) + + [pA_2: string]: ITopType_2; +>pA_2 : Symbol(pA_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 34, 3)) +>ITopType_2 : Symbol(ITopType_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 23, 2)) + + [pB_2: `sub_${string}`]: ISubType_2; +>pB_2 : Symbol(pB_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 35, 3)) +>ISubType_2 : Symbol(ISubType_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 27, 1)) +} + +const testObj2: ITestInteface_2 = { +>testObj2 : Symbol(testObj2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 38, 5)) +>ITestInteface_2 : Symbol(ITestInteface_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 31, 1)) + + a: { tKey_2: "tVal_2 " }, +>a : Symbol(a, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 38, 35)) +>tKey_2 : Symbol(tKey_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 39, 6)) + + sub_b: { tKey_2: "tVal_2 ", sKey_2: "sVal_2" }, +>sub_b : Symbol(sub_b, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 39, 27)) +>tKey_2 : Symbol(tKey_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 40, 10)) +>sKey_2 : Symbol(sKey_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 40, 29)) + +}; + +const testObj2_2: ITestInteface_2 = { +>testObj2_2 : Symbol(testObj2_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 43, 5)) +>ITestInteface_2 : Symbol(ITestInteface_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 31, 1)) + + a: { tKey_2: "tVal_2 " }, +>a : Symbol(a, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 43, 37)) +>tKey_2 : Symbol(tKey_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 44, 6)) + + sub_b: { tKey_2: "tVal_2 ", sKey_2: "sVal_2", extra: "val3" }, +>sub_b : Symbol(sub_b, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 44, 27)) +>tKey_2 : Symbol(tKey_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 45, 10)) +>sKey_2 : Symbol(sKey_2, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 45, 29)) +>extra : Symbol(extra, Decl(excessPropertyCheckWithMultipleIndexSignatures1.ts, 45, 47)) + +}; + diff --git a/tests/baselines/reference/excessPropertyCheckWithMultipleIndexSignatures1.types b/tests/baselines/reference/excessPropertyCheckWithMultipleIndexSignatures1.types new file mode 100644 index 0000000000000..0f1e973f7dbe3 --- /dev/null +++ b/tests/baselines/reference/excessPropertyCheckWithMultipleIndexSignatures1.types @@ -0,0 +1,185 @@ +//// [tests/cases/compiler/excessPropertyCheckWithMultipleIndexSignatures1.ts] //// + +=== excessPropertyCheckWithMultipleIndexSignatures1.ts === +// https://github.com/microsoft/TypeScript/issues/58442 + +interface ITopType { + tKey: string; +>tKey : string +> : ^^^^^^ +} + +interface ISubType extends ITopType { + sKey: string; +>sKey : string +> : ^^^^^^ +} + +interface ITestInteface { + [pA: string]: ITopType; +>pA : string +> : ^^^^^^ + + [pB: number]: ISubType; +>pB : number +> : ^^^^^^ +} + +const testObj1: ITestInteface = { +>testObj1 : ITestInteface +> : ^^^^^^^^^^^^^ +>{ a: { tKey: "tVal" }, 1: { tKey: "tVal", sKey: "sVal" },} : { a: { tKey: string; }; 1: { tKey: string; sKey: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + a: { tKey: "tVal" }, +>a : { tKey: string; } +> : ^^^^^^^^^^^^^^^^^ +>{ tKey: "tVal" } : { tKey: string; } +> : ^^^^^^^^^^^^^^^^^ +>tKey : string +> : ^^^^^^ +>"tVal" : "tVal" +> : ^^^^^^ + + 1: { tKey: "tVal", sKey: "sVal" }, +>1 : { tKey: string; sKey: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ tKey: "tVal", sKey: "sVal" } : { tKey: string; sKey: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>tKey : string +> : ^^^^^^ +>"tVal" : "tVal" +> : ^^^^^^ +>sKey : string +> : ^^^^^^ +>"sVal" : "sVal" +> : ^^^^^^ + +}; + +const testObj1_2: ITestInteface = { +>testObj1_2 : ITestInteface +> : ^^^^^^^^^^^^^ +>{ a: { tKey: "tVal" }, 1: { tKey: "tVal", sKey: "sVal", extra: "val3" },} : { a: { tKey: string; }; 1: { tKey: string; sKey: string; extra: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + a: { tKey: "tVal" }, +>a : { tKey: string; } +> : ^^^^^^^^^^^^^^^^^ +>{ tKey: "tVal" } : { tKey: string; } +> : ^^^^^^^^^^^^^^^^^ +>tKey : string +> : ^^^^^^ +>"tVal" : "tVal" +> : ^^^^^^ + + 1: { tKey: "tVal", sKey: "sVal", extra: "val3" }, +>1 : { tKey: string; sKey: string; extra: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ tKey: "tVal", sKey: "sVal", extra: "val3" } : { tKey: string; sKey: string; extra: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>tKey : string +> : ^^^^^^ +>"tVal" : "tVal" +> : ^^^^^^ +>sKey : string +> : ^^^^^^ +>"sVal" : "sVal" +> : ^^^^^^ +>extra : string +> : ^^^^^^ +>"val3" : "val3" +> : ^^^^^^ + +}; + +interface ITopType_2 { + tKey_2: string; +>tKey_2 : string +> : ^^^^^^ +} + +interface ISubType_2 extends ITopType_2 { + sKey_2: string; +>sKey_2 : string +> : ^^^^^^ +} + +interface ITestInteface_2 { + [pA_2: string]: ITopType_2; +>pA_2 : string +> : ^^^^^^ + + [pB_2: `sub_${string}`]: ISubType_2; +>pB_2 : `sub_${string}` +> : ^^^^^^^^^^^^^^^ +} + +const testObj2: ITestInteface_2 = { +>testObj2 : ITestInteface_2 +> : ^^^^^^^^^^^^^^^ +>{ a: { tKey_2: "tVal_2 " }, sub_b: { tKey_2: "tVal_2 ", sKey_2: "sVal_2" },} : { a: { tKey_2: string; }; sub_b: { tKey_2: string; sKey_2: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + a: { tKey_2: "tVal_2 " }, +>a : { tKey_2: string; } +> : ^^^^^^^^^^^^^^^^^^^ +>{ tKey_2: "tVal_2 " } : { tKey_2: string; } +> : ^^^^^^^^^^^^^^^^^^^ +>tKey_2 : string +> : ^^^^^^ +>"tVal_2 " : "tVal_2 " +> : ^^^^^^^^^ + + sub_b: { tKey_2: "tVal_2 ", sKey_2: "sVal_2" }, +>sub_b : { tKey_2: string; sKey_2: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ tKey_2: "tVal_2 ", sKey_2: "sVal_2" } : { tKey_2: string; sKey_2: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>tKey_2 : string +> : ^^^^^^ +>"tVal_2 " : "tVal_2 " +> : ^^^^^^^^^ +>sKey_2 : string +> : ^^^^^^ +>"sVal_2" : "sVal_2" +> : ^^^^^^^^ + +}; + +const testObj2_2: ITestInteface_2 = { +>testObj2_2 : ITestInteface_2 +> : ^^^^^^^^^^^^^^^ +>{ a: { tKey_2: "tVal_2 " }, sub_b: { tKey_2: "tVal_2 ", sKey_2: "sVal_2", extra: "val3" },} : { a: { tKey_2: string; }; sub_b: { tKey_2: string; sKey_2: string; extra: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + a: { tKey_2: "tVal_2 " }, +>a : { tKey_2: string; } +> : ^^^^^^^^^^^^^^^^^^^ +>{ tKey_2: "tVal_2 " } : { tKey_2: string; } +> : ^^^^^^^^^^^^^^^^^^^ +>tKey_2 : string +> : ^^^^^^ +>"tVal_2 " : "tVal_2 " +> : ^^^^^^^^^ + + sub_b: { tKey_2: "tVal_2 ", sKey_2: "sVal_2", extra: "val3" }, +>sub_b : { tKey_2: string; sKey_2: string; extra: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ tKey_2: "tVal_2 ", sKey_2: "sVal_2", extra: "val3" } : { tKey_2: string; sKey_2: string; extra: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>tKey_2 : string +> : ^^^^^^ +>"tVal_2 " : "tVal_2 " +> : ^^^^^^^^^ +>sKey_2 : string +> : ^^^^^^ +>"sVal_2" : "sVal_2" +> : ^^^^^^^^ +>extra : string +> : ^^^^^^ +>"val3" : "val3" +> : ^^^^^^ + +}; + diff --git a/tests/cases/compiler/commonPropertyCheckWithMultipleIndexSignatures1.ts b/tests/cases/compiler/commonPropertyCheckWithMultipleIndexSignatures1.ts new file mode 100644 index 0000000000000..816da975e577f --- /dev/null +++ b/tests/cases/compiler/commonPropertyCheckWithMultipleIndexSignatures1.ts @@ -0,0 +1,48 @@ +// @strict: true +// @noEmit: true + +interface ITopType { + tKey?: string; +} + +interface ISubType extends ITopType { + sKey?: string; +} + +interface ITestInteface { + [pA: string]: ITopType; + [pB: number]: ISubType; +} + +const testObj1: ITestInteface = { + a: { tKey: "tVal" }, + 1: { tKey: "tVal", sKey: "sVal" }, +}; + +const testObj1_2: ITestInteface = { + a: { tKey: "tVal" }, + 1: { notCommon: "val3" }, +}; + +interface ITopType_2 { + tKey_2?: string; +} + +interface ISubType_2 extends ITopType_2 { + sKey_2?: string; +} + +interface ITestInteface_2 { + [pA_2: string]: ITopType_2; + [pB_2: `sub_${string}`]: ISubType_2; +} + +const testObj2: ITestInteface_2 = { + a: { tKey_2: "tVal_2 " }, + sub_b: { tKey_2: "tVal_2 ", sKey_2: "sVal_2" }, +}; + +const testObj2_2: ITestInteface_2 = { + a: { tKey_2: "tVal_2 " }, + sub_b: { notCommon: "val3" }, +}; diff --git a/tests/cases/compiler/excessPropertyCheckWithMultipleIndexSignatures1.ts b/tests/cases/compiler/excessPropertyCheckWithMultipleIndexSignatures1.ts new file mode 100644 index 0000000000000..1001d7d5408d7 --- /dev/null +++ b/tests/cases/compiler/excessPropertyCheckWithMultipleIndexSignatures1.ts @@ -0,0 +1,50 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/58442 + +interface ITopType { + tKey: string; +} + +interface ISubType extends ITopType { + sKey: string; +} + +interface ITestInteface { + [pA: string]: ITopType; + [pB: number]: ISubType; +} + +const testObj1: ITestInteface = { + a: { tKey: "tVal" }, + 1: { tKey: "tVal", sKey: "sVal" }, +}; + +const testObj1_2: ITestInteface = { + a: { tKey: "tVal" }, + 1: { tKey: "tVal", sKey: "sVal", extra: "val3" }, +}; + +interface ITopType_2 { + tKey_2: string; +} + +interface ISubType_2 extends ITopType_2 { + sKey_2: string; +} + +interface ITestInteface_2 { + [pA_2: string]: ITopType_2; + [pB_2: `sub_${string}`]: ISubType_2; +} + +const testObj2: ITestInteface_2 = { + a: { tKey_2: "tVal_2 " }, + sub_b: { tKey_2: "tVal_2 ", sKey_2: "sVal_2" }, +}; + +const testObj2_2: ITestInteface_2 = { + a: { tKey_2: "tVal_2 " }, + sub_b: { tKey_2: "tVal_2 ", sKey_2: "sVal_2", extra: "val3" }, +};