@@ -3524,7 +3524,7 @@ namespace ts {
3524
3524
if (resolvedType.indexInfos) {
3525
3525
for (let info of resolvedType.indexInfos) {
3526
3526
if (resolvedType.objectFlags & ObjectFlags.ReverseMapped) {
3527
- info = createIndexInfo(info.indexType, anyType, info.isReadonly, info.declaration);
3527
+ info = createIndexInfo(info.indexType, anyType, info.isReadonly, info.declaration);
3528
3528
}
3529
3529
typeElements.push(indexInfoToIndexSignatureDeclarationHelper(info, context));
3530
3530
}
@@ -6696,9 +6696,9 @@ namespace ts {
6696
6696
const readonlyMask = modifiers & MappedTypeModifiers.IncludeReadonly ? false : true;
6697
6697
const optionalMask = modifiers & MappedTypeModifiers.IncludeOptional ? 0 : SymbolFlags.Optional;
6698
6698
// TODO: Fix #26724 using the below once #26725 is fixed and `mappedRecursiveInference.ts` doesn't blow up with the change
6699
- //const mappedIndexInfos = indexInfos && map(indexInfos, indexInfo =>
6699
+ // const mappedIndexInfos = indexInfos && map(indexInfos, indexInfo =>
6700
6700
// createIndexInfo(indexInfo.indexType, inferReverseMappedType(indexInfo.type, type.mappedType), readonlyMask && indexInfo.isReadonly)
6701
- //);
6701
+ // );
6702
6702
const mappedIndexInfos = map(filter(indexInfos, i => !!(i.indexType.flags & TypeFlags.String)), i => createIndexInfo(i.indexType, inferReverseMappedType(i.type, type.mappedType), readonlyMask && i.isReadonly));
6703
6703
const members = createSymbolTable();
6704
6704
for (const prop of getPropertiesOfType(type.source)) {
@@ -7428,15 +7428,15 @@ namespace ts {
7428
7428
return resolveIndexOnIndexInfos(indexType, getIndexInfosOfType(type));
7429
7429
}
7430
7430
7431
- function getApplicableIndexInfosOfIndexOnType(type: Type, indexType: Type, contravariant ?: boolean): IndexInfo[] | undefined {
7431
+ function getApplicableIndexInfosOfIndexOnType(type: Type, indexType: Type, returnPartialSuccess ?: boolean): IndexInfo[] | undefined {
7432
7432
if (!(indexType.flags & TypeFlags.Union)) {
7433
7433
const result = getResultingIndexInfoOfIndexOnType(type, indexType);
7434
7434
return result && [result];
7435
7435
}
7436
7436
let resultList: IndexInfo[] | undefined;
7437
7437
for (const nameType of (indexType as UnionType).types) {
7438
7438
const result = getResultingIndexInfoOfIndexOnType(type, nameType);
7439
- if (!result && !contravariant ) {
7439
+ if (!result && !returnPartialSuccess ) {
7440
7440
return;
7441
7441
}
7442
7442
if (result) {
@@ -7446,8 +7446,8 @@ namespace ts {
7446
7446
return resultList;
7447
7447
}
7448
7448
7449
- function getResultingTypeOfIndexOnType(type: Type, indexType: Type, contravariant ?: boolean): Type | undefined {
7450
- const resultInfos = getApplicableIndexInfosOfIndexOnType(type, indexType, contravariant );
7449
+ function getResultingTypeOfIndexOnType(type: Type, indexType: Type, returnPartialSuccess ?: boolean): Type | undefined {
7450
+ const resultInfos = getApplicableIndexInfosOfIndexOnType(type, indexType, returnPartialSuccess );
7451
7451
return resultInfos && getUnionType(map(resultInfos, i => i.type));
7452
7452
}
7453
7453
@@ -9212,7 +9212,7 @@ namespace ts {
9212
9212
const base = getUnionType([
9213
9213
filterType(getUnionType(map(filter(getIndexInfosOfType(type) || emptyArray, info => info !== enumNumberIndexInfo), t => t.indexType)), t => !stringsOnly || isTypeAssignableTo(t, stringType)),
9214
9214
getLiteralTypeFromPropertyNames(type, stringsOnly ? TypeFlags.StringLiteral : TypeFlags.StringOrNumberLiteralOrUnique),
9215
- ])
9215
+ ]);
9216
9216
if (!stringsOnly && maybeTypeOfKind(base, TypeFlags.String)) {
9217
9217
return getUnionType([base, numberType]);
9218
9218
}
@@ -10988,7 +10988,7 @@ namespace ts {
10988
10988
return t.properties.length === 0 &&
10989
10989
t.callSignatures.length === 0 &&
10990
10990
t.constructSignatures.length === 0 &&
10991
- !length(t.indexInfos)
10991
+ !length(t.indexInfos);
10992
10992
}
10993
10993
10994
10994
function isEmptyObjectType(type: Type): boolean {
@@ -12289,7 +12289,9 @@ namespace ts {
12289
12289
if (isIgnoredJsxProperty(source, prop, /*targetMemberType*/ undefined)) {
12290
12290
continue;
12291
12291
}
12292
- const targetType = getResultingTypeOfIndexOnType(target, getLiteralTypeFromPropertyName(prop, TypeFlags.StringOrNumberLiteralOrUnique));
12292
+ const nameType = getLiteralTypeFromPropertyName(prop, TypeFlags.StringOrNumberLiteralOrUnique);
12293
+ if (nameType.flags & TypeFlags.Never) continue;
12294
+ const targetType = getResultingTypeOfIndexOnType(target, nameType);
12293
12295
if (targetType) {
12294
12296
const related = isRelatedTo(getTypeOfSymbol(prop), targetType, reportErrors);
12295
12297
if (!related) {
@@ -12312,10 +12314,9 @@ namespace ts {
12312
12314
if (!targetInfo) {
12313
12315
return Ternary.True;
12314
12316
}
12315
- const sourceInfo = getIndexInfosOfType(source)
12316
- const result = sourceInfo && indexInfosRelated(sourceInfo, targetInfo, sourceIsPrimitive, reportErrors);
12317
- if (result !== undefined && result !== Ternary.Maybe) {
12318
- return result;
12317
+ const sourceInfo = getIndexInfosOfType(source);
12318
+ if (sourceInfo) {
12319
+ return indexInfosRelated(source, target, sourceIsPrimitive, reportErrors);
12319
12320
}
12320
12321
if (isGenericMappedType(source)) {
12321
12322
// A generic mapped type { [P in K]: T } is related to an index signature { [x: string]: U }
@@ -12357,20 +12358,6 @@ namespace ts {
12357
12358
return Ternary.False;
12358
12359
}
12359
12360
12360
- function isIndexTypeRelatedTo(source: IndexInfo, target: IndexInfo, sourceIsPrimitive: boolean, reportErrors: boolean, skipIndexError?: boolean): Ternary {
12361
- // Index signature of type any permits assignment from everything but primitives
12362
- if (!sourceIsPrimitive && target.type.flags & TypeFlags.AnyOrUnknown) {
12363
- return Ternary.True;
12364
- }
12365
- const related = isRelatedTo(source.type, target.type, reportErrors);
12366
- if (!related && reportErrors && !skipIndexError) {
12367
- const sourceType = typeToString(source.indexType);
12368
- const targetType = typeToString(target.indexType);
12369
- reportError(sourceType === targetType ? Diagnostics._0_index_signatures_are_incompatible : Diagnostics._0_and_1_index_signatures_are_incompatible, sourceType, targetType);
12370
- }
12371
- return related;
12372
- }
12373
-
12374
12361
function indexInfosIdentical(sourceInfos: IndexInfo[] | undefined, targetInfos: IndexInfo[] | undefined) {
12375
12362
if (length(sourceInfos) !== length(targetInfos)) return Ternary.False;
12376
12363
if (!sourceInfos || !targetInfos) return Ternary.True;
@@ -12393,28 +12380,46 @@ namespace ts {
12393
12380
return Ternary.True;
12394
12381
}
12395
12382
12396
- function indexInfosRelated(sourceInfos: IndexInfo[] | undefined, targetInfos: IndexInfo[] | undefined , sourceIsPrimitive: boolean, reportErrors: boolean): Ternary {
12397
- if (!sourceInfos && !targetInfos) {
12398
- return Ternary.True ;
12399
- }
12400
- if (sourceInfos && targetInfos) {
12401
- // If for every index signature in S there exists a related signature in T
12402
- targetLoop: for (const targetInfo of targetInfos ) {
12403
- for (const sourceInfo of sourceInfos) {
12404
- if (isTypeIndexAssignableTo(sourceInfo.indexType, targetInfo.indexType)) {
12405
- if (!isIndexTypeRelatedTo(sourceInfo , targetInfo, sourceIsPrimitive, reportErrors)) return Ternary.False ;
12406
- if (relation === identityRelation && sourceInfo.isReadonly !== targetInfo.isReadonly) return Ternary.False;
12407
- continue targetLoop;
12408
- }
12383
+ function indexInfosRelated(source: Type, target: Type , sourceIsPrimitive: boolean, reportErrors: boolean): Ternary {
12384
+ const targetInfos = getIndexInfosOfType(target);
12385
+ if (!targetInfos) return Debug.fail("Existance of index infos in target should have been checked beforehand") ;
12386
+ const sourceHasInferableIndex = isObjectTypeWithInferableIndex(source);
12387
+ let result = Ternary.True;
12388
+ for (const targetInfo of targetInfos) {
12389
+ if (!sourceIsPrimitive && targetInfo.type.flags & TypeFlags.AnyOrUnknown ) {
12390
+ continue;
12391
+ }
12392
+ const indexingResult = getResultingTypeOfIndexOnType(source , targetInfo.indexType, sourceHasInferableIndex) ;
12393
+ if (!indexingResult) {
12394
+ if (sourceHasInferableIndex) {
12395
+ continue;
12409
12396
}
12410
- if (targetInfo === targetInfos[targetInfos.length - 1] ) {
12411
- return Ternary.Maybe; // Iterated over every target signature without a definitive yes or no on every signature; allow fallback to inferred signature
12397
+ if (reportErrors ) {
12398
+ reportError(Diagnostics.Index_signature_is_missing_in_type_0, typeToString(source));
12412
12399
}
12400
+ return Ternary.False;
12401
+ }
12402
+ result &= isRelatedTo(indexingResult, targetInfo.type, reportErrors);
12403
+ if (!result) {
12404
+ if (reportErrors) {
12405
+ const sourceInfos = getApplicableIndexInfosOfIndexOnType(source, targetInfo.indexType, sourceHasInferableIndex);
12406
+ for (const info of sourceInfos!) {
12407
+ if (!isRelatedTo(info.type, targetInfo.type)) {
12408
+ const sourceType = typeToString(info.indexType);
12409
+ const targetType = typeToString(targetInfo.indexType);
12410
+ reportError(sourceType === targetType ? Diagnostics._0_index_signatures_are_incompatible : Diagnostics._0_and_1_index_signatures_are_incompatible, sourceType, targetType);
12411
+ break;
12412
+ }
12413
+ }
12414
+ }
12415
+ return result;
12413
12416
}
12414
- // Then the signature lists are related
12415
- return Ternary.True;
12416
12417
}
12417
- return Ternary.False;
12418
+ if (result && sourceHasInferableIndex) {
12419
+ // A type with an inferable index, provided none of its indexes are strictly incompatible, is compatible so long as its existing props are compatible
12420
+ result &= eachPropertyRelatedToIndexesOf(source, target, reportErrors);
12421
+ }
12422
+ return result;
12418
12423
}
12419
12424
12420
12425
function constructorVisibilitiesAreCompatible(sourceSignature: Signature, targetSignature: Signature, reportErrors: boolean) {
@@ -25305,7 +25310,7 @@ namespace ts {
25305
25310
function checkIndexConstraints(type: Type) {
25306
25311
const declaredIndexers = getIndexDeclarationsOfSymbol(type.symbol);
25307
25312
const indexInfos = getIndexInfosOfType(type);
25308
-
25313
+
25309
25314
if (indexInfos) {
25310
25315
forEach(getPropertiesOfObjectType(type), prop => {
25311
25316
const propType = getTypeOfSymbol(prop);
@@ -25365,10 +25370,10 @@ namespace ts {
25365
25370
typeToString(info2.indexType),
25366
25371
typeToString(info2.type)
25367
25372
);
25368
- checkTypeAssignableTo(info1.type, info2.type, errorNode, undefined, rootChain);
25373
+ checkTypeAssignableTo(info1.type, info2.type, errorNode, /*diagnosticMessage*/ undefined, rootChain);
25369
25374
}
25370
25375
}
25371
- })
25376
+ });
25372
25377
}
25373
25378
}
25374
25379
0 commit comments