Skip to content

Commit 8dad1d4

Browse files
committed
bugfix: homomorphic mapped types when T is non-generic, solves 27995
1 parent f4d76e5 commit 8dad1d4

File tree

1 file changed

+24
-8
lines changed

1 file changed

+24
-8
lines changed

src/compiler/checker.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15848,6 +15848,19 @@ namespace ts {
1584815848
// Eagerly resolve the constraint type which forces an error if the constraint type circularly
1584915849
// references itself through one or more type aliases.
1585015850
getConstraintTypeFromMappedType(type);
15851+
// Detect if the mapped type should be homomorphic to a tuple by checking the declaration of the constraint if it contains a keyof over a tuple
15852+
if (node.typeParameter.constraint && isTypeOperatorNode(node.typeParameter.constraint) && node.typeParameter.constraint.operator === SyntaxKind.KeyOfKeyword) {
15853+
const keyOfTarget = getTypeFromTypeNode(node.typeParameter.constraint.type);
15854+
if (isTupleType(keyOfTarget)) {
15855+
// Instantiate the mapped type over a tuple with an identity mapper
15856+
const instantiatedTupleMappedType = instantiateMappedTupleType(
15857+
keyOfTarget,
15858+
type,
15859+
makeFunctionTypeMapper(identity)
15860+
);
15861+
links.resolvedType = instantiatedTupleMappedType;
15862+
}
15863+
}
1585115864
}
1585215865
return links.resolvedType;
1585315866
}
@@ -35579,14 +35592,17 @@ namespace ts {
3557935592
reportImplicitAny(node, anyType);
3558035593
}
3558135594

35582-
const type = getTypeFromMappedTypeNode(node) as MappedType;
35583-
const nameType = getNameTypeFromMappedType(type);
35584-
if (nameType) {
35585-
checkTypeAssignableTo(nameType, keyofConstraintType, node.nameType);
35586-
}
35587-
else {
35588-
const constraintType = getConstraintTypeFromMappedType(type);
35589-
checkTypeAssignableTo(constraintType, keyofConstraintType, getEffectiveConstraintOfTypeParameter(node.typeParameter));
35595+
const type = getTypeFromMappedTypeNode(node);
35596+
// Continue to check if the type returned is a mapped type, that means it wasn't resolved to a homomorphic tuple type
35597+
if (type.flags & TypeFlags.Object && (type as ObjectType).objectFlags & ObjectFlags.Mapped) {
35598+
const nameType = getNameTypeFromMappedType(type as MappedType);
35599+
if (nameType) {
35600+
checkTypeAssignableTo(nameType, keyofConstraintType, node.nameType);
35601+
}
35602+
else {
35603+
const constraintType = getConstraintTypeFromMappedType(type as MappedType);
35604+
checkTypeAssignableTo(constraintType, keyofConstraintType, getEffectiveConstraintOfTypeParameter(node.typeParameter));
35605+
}
3559035606
}
3559135607
}
3559235608

0 commit comments

Comments
 (0)