Skip to content

Commit bf72587

Browse files
committed
Improve type relationships for generic mapped types
1 parent 04da707 commit bf72587

File tree

1 file changed

+15
-20
lines changed

1 file changed

+15
-20
lines changed

src/compiler/checker.ts

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4662,10 +4662,6 @@ namespace ts {
46624662
return type.modifiersType;
46634663
}
46644664

4665-
function getErasedTemplateTypeFromMappedType(type: MappedType) {
4666-
return instantiateType(getTemplateTypeFromMappedType(type), createTypeEraser([getTypeParameterFromMappedType(type)]));
4667-
}
4668-
46694665
function isGenericMappedType(type: Type) {
46704666
if (getObjectFlags(type) & ObjectFlags.Mapped) {
46714667
const constraintType = getConstraintTypeFromMappedType(<MappedType>type);
@@ -7765,25 +7761,24 @@ namespace ts {
77657761
return result;
77667762
}
77677763

7768-
// A type [P in S]: X is related to a type [P in T]: Y if T is related to S and X is related to Y.
7764+
// A type [P in S]: X is related to a type [Q in T]: Y if T is related to S and X' is
7765+
// related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice
7766+
// that S and T are contra-variant whereas X and Y are co-variant.
77697767
function mappedTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
77707768
if (isGenericMappedType(target)) {
77717769
if (isGenericMappedType(source)) {
7772-
let result: Ternary;
7773-
if (relation === identityRelation) {
7774-
const readonlyMatches = !(<MappedType>source).declaration.readonlyToken === !(<MappedType>target).declaration.readonlyToken;
7775-
const optionalMatches = !(<MappedType>source).declaration.questionToken === !(<MappedType>target).declaration.questionToken;
7776-
if (readonlyMatches && optionalMatches) {
7777-
if (result = isRelatedTo(getConstraintTypeFromMappedType(<MappedType>target), getConstraintTypeFromMappedType(<MappedType>source), reportErrors)) {
7778-
return result & isRelatedTo(getErasedTemplateTypeFromMappedType(<MappedType>source), getErasedTemplateTypeFromMappedType(<MappedType>target), reportErrors);
7779-
}
7780-
}
7781-
}
7782-
else {
7783-
if (relation === comparableRelation || !(<MappedType>source).declaration.questionToken || (<MappedType>target).declaration.questionToken) {
7784-
if (result = isRelatedTo(getConstraintTypeFromMappedType(<MappedType>target), getConstraintTypeFromMappedType(<MappedType>source), reportErrors)) {
7785-
return result & isRelatedTo(getTemplateTypeFromMappedType(<MappedType>source), getTemplateTypeFromMappedType(<MappedType>target), reportErrors);
7786-
}
7770+
const sourceReadonly = !!(<MappedType>source).declaration.readonlyToken;
7771+
const sourceOptional = !!(<MappedType>source).declaration.questionToken;
7772+
const targetReadonly = !!(<MappedType>target).declaration.readonlyToken;
7773+
const targetOptional = !!(<MappedType>target).declaration.questionToken;
7774+
const modifiersRelated = relation === identityRelation ?
7775+
sourceReadonly === targetReadonly && sourceOptional === targetOptional :
7776+
relation === comparableRelation || !sourceOptional || targetOptional;
7777+
if (modifiersRelated) {
7778+
let result: Ternary;
7779+
if (result = isRelatedTo(getConstraintTypeFromMappedType(<MappedType>target), getConstraintTypeFromMappedType(<MappedType>source), reportErrors)) {
7780+
const mapper = createTypeMapper([getTypeParameterFromMappedType(<MappedType>source)], [getTypeParameterFromMappedType(<MappedType>target)]);
7781+
return result & isRelatedTo(instantiateType(getTemplateTypeFromMappedType(<MappedType>source), mapper), getTemplateTypeFromMappedType(<MappedType>target), reportErrors);
77877782
}
77887783
}
77897784
}

0 commit comments

Comments
 (0)