Skip to content

Commit 47e6aef

Browse files
committed
Given T extends Foo, make Partial<T> related to Partial<Foo>
1 parent 8fa1d2e commit 47e6aef

File tree

1 file changed

+25
-34
lines changed

1 file changed

+25
-34
lines changed

src/compiler/checker.ts

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5765,12 +5765,13 @@ namespace ts {
57655765
return type.modifiersType;
57665766
}
57675767

5768+
function isPartialMappedType(type: Type) {
5769+
return getObjectFlags(type) & ObjectFlags.Mapped && !!(<MappedType>type).declaration.questionToken;
5770+
}
5771+
57685772
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);
57745775
}
57755776

57765777
function resolveStructuredTypeMembers(type: StructuredType): ResolvedType {
@@ -9254,8 +9255,12 @@ namespace ts {
92549255
if (source.flags & (TypeFlags.Object | TypeFlags.Intersection) && target.flags & TypeFlags.Object) {
92559256
// Report structural errors only if we haven't reported any errors yet
92569257
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;
92599264
}
92609265
else {
92619266
result = propertiesRelatedTo(source, target, reportStructuralErrors);
@@ -9284,33 +9289,19 @@ namespace ts {
92849289
// A type [P in S]: X is related to a type [Q in T]: Y if T is related to S and X' is
92859290
// related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice
92869291
// 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);
93149305
}
93159306
}
93169307
return Ternary.False;

0 commit comments

Comments
 (0)