@@ -5765,12 +5765,13 @@ namespace ts {
5765
5765
return type.modifiersType;
5766
5766
}
5767
5767
5768
+ function isPartialMappedType(type: Type) {
5769
+ return getObjectFlags(type) & ObjectFlags.Mapped && !!(<MappedType>type).declaration.questionToken;
5770
+ }
5771
+
5768
5772
function isGenericMappedType(type: Type) {
5769
- if (getObjectFlags(type) & ObjectFlags.Mapped) {
5770
- const constraintType = getConstraintTypeFromMappedType(<MappedType>type);
5771
- return maybeTypeOfKind(constraintType, TypeFlags.TypeVariable | TypeFlags.Index);
5772
- }
5773
- return false;
5773
+ return getObjectFlags(type) & ObjectFlags.Mapped &&
5774
+ maybeTypeOfKind(getConstraintTypeFromMappedType(<MappedType>type), TypeFlags.TypeVariable | TypeFlags.Index);
5774
5775
}
5775
5776
5776
5777
function resolveStructuredTypeMembers(type: StructuredType): ResolvedType {
@@ -9254,8 +9255,12 @@ namespace ts {
9254
9255
if (source.flags & (TypeFlags.Object | TypeFlags.Intersection) && target.flags & TypeFlags.Object) {
9255
9256
// Report structural errors only if we haven't reported any errors yet
9256
9257
const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo && !sourceIsPrimitive;
9257
- if (isGenericMappedType(source) || isGenericMappedType(target)) {
9258
- result = mappedTypeRelatedTo(source, target, reportStructuralErrors);
9258
+ // An empty object type is related to any mapped type that includes a '?' modifier.
9259
+ if (isPartialMappedType(target) && !isGenericMappedType(source) && isEmptyObjectType(source)) {
9260
+ result = Ternary.True;
9261
+ }
9262
+ else if (isGenericMappedType(target)) {
9263
+ result = isGenericMappedType(source) ? mappedTypeRelatedTo(<MappedType>source, <MappedType>target, reportStructuralErrors) : Ternary.False;
9259
9264
}
9260
9265
else {
9261
9266
result = propertiesRelatedTo(source, target, reportStructuralErrors);
@@ -9284,33 +9289,19 @@ namespace ts {
9284
9289
// A type [P in S]: X is related to a type [Q in T]: Y if T is related to S and X' is
9285
9290
// related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice
9286
9291
// that S and T are contra-variant whereas X and Y are co-variant.
9287
- function mappedTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
9288
- if (isGenericMappedType(target)) {
9289
- if (isGenericMappedType(source)) {
9290
- const sourceReadonly = !!(<MappedType>source).declaration.readonlyToken;
9291
- const sourceOptional = !!(<MappedType>source).declaration.questionToken;
9292
- const targetReadonly = !!(<MappedType>target).declaration.readonlyToken;
9293
- const targetOptional = !!(<MappedType>target).declaration.questionToken;
9294
- const modifiersRelated = relation === identityRelation ?
9295
- sourceReadonly === targetReadonly && sourceOptional === targetOptional :
9296
- relation === comparableRelation || !sourceOptional || targetOptional;
9297
- if (modifiersRelated) {
9298
- let result: Ternary;
9299
- if (result = isRelatedTo(getConstraintTypeFromMappedType(<MappedType>target), getConstraintTypeFromMappedType(<MappedType>source), reportErrors)) {
9300
- const mapper = createTypeMapper([getTypeParameterFromMappedType(<MappedType>source)], [getTypeParameterFromMappedType(<MappedType>target)]);
9301
- return result & isRelatedTo(instantiateType(getTemplateTypeFromMappedType(<MappedType>source), mapper), getTemplateTypeFromMappedType(<MappedType>target), reportErrors);
9302
- }
9303
- }
9304
- }
9305
- else if ((<MappedType>target).declaration.questionToken && isEmptyObjectType(source)) {
9306
- return Ternary.True;
9307
-
9308
- }
9309
- }
9310
- else if (relation !== identityRelation) {
9311
- const resolved = resolveStructuredTypeMembers(<ObjectType>target);
9312
- if (isEmptyResolvedType(resolved) || resolved.stringIndexInfo && resolved.stringIndexInfo.type.flags & TypeFlags.Any) {
9313
- return Ternary.True;
9292
+ function mappedTypeRelatedTo(source: MappedType, target: MappedType, reportErrors: boolean): Ternary {
9293
+ const sourceReadonly = !!source.declaration.readonlyToken;
9294
+ const sourceOptional = !!source.declaration.questionToken;
9295
+ const targetReadonly = !!target.declaration.readonlyToken;
9296
+ const targetOptional = !!target.declaration.questionToken;
9297
+ const modifiersRelated = relation === identityRelation ?
9298
+ sourceReadonly === targetReadonly && sourceOptional === targetOptional :
9299
+ relation === comparableRelation || !sourceOptional || targetOptional;
9300
+ if (modifiersRelated) {
9301
+ let result: Ternary;
9302
+ if (result = isRelatedTo(getConstraintTypeFromMappedType(<MappedType>target), getConstraintTypeFromMappedType(<MappedType>source), reportErrors)) {
9303
+ const mapper = createTypeMapper([getTypeParameterFromMappedType(<MappedType>source)], [getTypeParameterFromMappedType(<MappedType>target)]);
9304
+ return result & isRelatedTo(instantiateType(getTemplateTypeFromMappedType(<MappedType>source), mapper), getTemplateTypeFromMappedType(<MappedType>target), reportErrors);
9314
9305
}
9315
9306
}
9316
9307
return Ternary.False;
0 commit comments