@@ -23464,22 +23464,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2346423464 return result;
2346523465 }
2346623466
23467- function getApparentMappedTypeKeys (nameType: Type, mappedType : MappedType, forSource: boolean ) {
23468- const modifiersType = getApparentType(getModifiersTypeFromMappedType(mappedType ));
23467+ function getApparentTargetMappedTypeKeys (nameType: Type, targetType : MappedType) {
23468+ const modifiersType = getApparentType(getModifiersTypeFromMappedType(targetType ));
2346923469 const mappedKeys: Type[] = [];
2347023470 forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType(
2347123471 modifiersType,
2347223472 TypeFlags.StringOrNumberLiteralOrUnique,
2347323473 /*stringsOnly*/ false,
23474- t => void mappedKeys.push(instantiateType(nameType, appendTypeMapping(mappedType .mapper, getTypeParameterFromMappedType(mappedType ), t))),
23474+ t => void mappedKeys.push(instantiateType(nameType, appendTypeMapping(targetType .mapper, getTypeParameterFromMappedType(targetType ), t))),
2347523475 );
23476- const apparentKeys = getUnionType(mappedKeys);
23477- if (forSource && apparentKeys.flags & TypeFlags.Never) {
23478- // modifiers type of mapped type is often `unknown`, `keyof unknown` is `never` and that's assignable to everything
23479- // letting this through is too permissive so we use the apparent type of an index type here instead
23480- return stringNumberSymbolType;
23481- }
23482- return apparentKeys;
23476+ return getUnionType(mappedKeys);
2348323477 }
2348423478
2348523479 function structuredTypeRelatedToWorker(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState, saveErrorInfo: ReturnType<typeof captureErrorCalculationState>): Ternary {
@@ -23632,6 +23626,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2363223626 return result;
2363323627 }
2363423628 }
23629+ if (sourceFlags & TypeFlags.TypeParameter && source.symbol && some(source.symbol.declarations, d => d.parent.kind === SyntaxKind.MappedType)) {
23630+ const constraint = getConstraintOfTypeParameter(source);
23631+ if (constraint && isRelatedTo(constraint, target, RecursionFlags.Both, /*reportErrors*/ false) === Ternary.True) {
23632+ return Ternary.True;
23633+ }
23634+ }
2363523635 if (isTupleType(targetType)) {
2363623636 // An index type can have a tuple type target when the tuple type contains variadic elements.
2363723637 // Check if the source is related to the known keys of the tuple type.
@@ -23663,7 +23663,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2366323663 if (nameType && isMappedTypeWithKeyofConstraintDeclaration(targetType)) {
2366423664 // we need to get the apparent mappings and union them with the generic mappings, since some properties may be
2366523665 // missing from the `constraintType` which will otherwise be mapped in the object
23666- const mappedKeys = getApparentMappedTypeKeys (nameType, targetType, /*forSource*/ false );
23666+ const mappedKeys = getApparentTargetMappedTypeKeys (nameType, targetType);
2366723667 // We still need to include the non-apparent (and thus still generic) keys in the target side of the comparison (in case they're in the source side)
2366823668 targetKeys = getUnionType([mappedKeys, nameType]);
2366923669 }
@@ -23865,12 +23865,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2386523865 if (isDeferredMappedIndex) {
2386623866 const mappedType = (source as IndexType).type as MappedType;
2386723867 const nameType = getNameTypeFromMappedType(mappedType);
23868- // Unlike on the target side, on the source side we do *not* include the generic part of the `nameType`, since that comes from a
23869- // (potentially anonymous) mapped type local type parameter, so that'd never assign outside the mapped type body, but we still want to
23870- // allow assignments of index types of identical (or similar enough) mapped types.
23871- // eg, `keyof {[X in keyof A]: Obj[X]}` should be assignable to `keyof {[Y in keyof A]: Tup[Y]}` because both map over the same set of keys (`keyof A`).
23872- // Without this source-side breakdown, a `keyof {[X in keyof A]: Obj[X]}` style type won't be assignable to anything except itself, which is much too strict.
23873- const sourceMappedKeys = nameType && isMappedTypeWithKeyofConstraintDeclaration(mappedType) ? getApparentMappedTypeKeys(nameType, mappedType, /*forSource*/ true) : (nameType || getConstraintTypeFromMappedType(mappedType));
23868+ const sourceMappedKeys = nameType || getConstraintTypeFromMappedType(mappedType);
2387423869 if (result = isRelatedTo(sourceMappedKeys, target, RecursionFlags.Source, reportErrors)) {
2387523870 return result;
2387623871 }
@@ -24117,7 +24112,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2411724112 const sourceConstraint = instantiateType(getConstraintTypeFromMappedType(source), getCombinedMappedTypeOptionality(source) < 0 ? reportUnmeasurableMapper : reportUnreliableMapper);
2411824113 if (result = isRelatedTo(targetConstraint, sourceConstraint, RecursionFlags.Both, reportErrors)) {
2411924114 const mapper = createTypeMapper([getTypeParameterFromMappedType(source)], [getTypeParameterFromMappedType(target)]);
24120- if (instantiateType(getNameTypeFromMappedType(source), mapper) === instantiateType(getNameTypeFromMappedType(target), mapper)) {
24115+ if (isTypeIdenticalTo( instantiateType(getNameTypeFromMappedType(source), mapper) ?? unknownType, instantiateType(getNameTypeFromMappedType(target), mapper) ?? unknownType )) {
2412124116 return result & isRelatedTo(instantiateType(getTemplateTypeFromMappedType(source), mapper), getTemplateTypeFromMappedType(target), RecursionFlags.Both, reportErrors);
2412224117 }
2412324118 }
0 commit comments