@@ -23484,10 +23484,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
23484
23484
// unique AST node.
23485
23485
return (type as TypeReference).node!;
23486
23486
}
23487
- if (type.symbol && !(getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol.flags & SymbolFlags.Class)) {
23488
- // We track all object types that have an associated symbol (representing the origin of the type), but
23489
- // exclude the static side of classes from this check since it shares its symbol with the instance side.
23490
- return type.symbol;
23487
+ if (type.symbol) {
23488
+ // We track object types that have a symbol by that symbol (representing the origin of the type).
23489
+ if (getObjectFlags(type) & ObjectFlags.Mapped) {
23490
+ // When a homomorphic mapped type is applied to a type with a symbol, we use the symbol of that
23491
+ // type as the recursion identity. This is a better strategy than using the symbol of the mapped
23492
+ // type, which doesn't work well for recursive mapped types.
23493
+ type = getMappedTargetWithSymbol(type);
23494
+ }
23495
+ if (!(getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol.flags & SymbolFlags.Class)) {
23496
+ // We exclude the static side of a class since it shares its symbol with the instance side.
23497
+ return type.symbol;
23498
+ }
23491
23499
}
23492
23500
if (isTupleType(type)) {
23493
23501
return type.target;
@@ -23511,6 +23519,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
23511
23519
return type;
23512
23520
}
23513
23521
23522
+ function getMappedTargetWithSymbol(type: Type) {
23523
+ let target = type;
23524
+ while ((getObjectFlags(target) & ObjectFlags.InstantiatedMapped) === ObjectFlags.InstantiatedMapped && isMappedTypeWithKeyofConstraintDeclaration(target as MappedType)) {
23525
+ target = getModifiersTypeFromMappedType(target as MappedType);
23526
+ }
23527
+ return target.symbol ? target : type;
23528
+ }
23529
+
23514
23530
function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean {
23515
23531
return compareProperties(sourceProp, targetProp, compareTypesIdentical) !== Ternary.False;
23516
23532
}
0 commit comments