@@ -14551,11 +14551,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
14551
14551
}
14552
14552
14553
14553
function getResolvedApparentTypeOfMappedType(type: MappedType) {
14554
- const typeVariable = getHomomorphicTypeVariable(type);
14555
- if (typeVariable && !type.declaration.nameType) {
14556
- const constraint = getConstraintOfTypeParameter(typeVariable);
14557
- if (constraint && everyType(constraint, isArrayOrTupleType)) {
14558
- return instantiateType(type, prependTypeMapping(typeVariable, constraint, type.mapper));
14554
+ const target = (type.target ?? type) as MappedType;
14555
+ const typeVariable = getHomomorphicTypeVariable(target);
14556
+ if (typeVariable && !target.declaration.nameType) {
14557
+ const constraint = getConstraintTypeFromMappedType(type);
14558
+ if (constraint.flags & TypeFlags.Index) {
14559
+ const baseConstraint = getBaseConstraintOfType((constraint as IndexType).type);
14560
+ if (baseConstraint && everyType(baseConstraint, isArrayOrTupleType)) {
14561
+ return instantiateType(target, prependTypeMapping(typeVariable, baseConstraint, type.mapper));
14562
+ }
14559
14563
}
14560
14564
}
14561
14565
return type;
@@ -20820,8 +20824,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
20820
20824
const restIndex = sourceRestType || targetRestType ? paramCount - 1 : -1;
20821
20825
20822
20826
for (let i = 0; i < paramCount; i++) {
20823
- const sourceType = i === restIndex ? getRestTypeAtPosition (source, i) : tryGetTypeAtPosition(source, i);
20824
- const targetType = i === restIndex ? getRestTypeAtPosition (target, i) : tryGetTypeAtPosition(target, i);
20827
+ const sourceType = i === restIndex ? getRestOrAnyTypeAtPosition (source, i) : tryGetTypeAtPosition(source, i);
20828
+ const targetType = i === restIndex ? getRestOrAnyTypeAtPosition (target, i) : tryGetTypeAtPosition(target, i);
20825
20829
if (sourceType && targetType) {
20826
20830
// In order to ensure that any generic type Foo<T> is at least co-variant with respect to T no matter
20827
20831
// how Foo uses T, we need to relate parameters bi-variantly (given that parameters are input positions,
@@ -36447,6 +36451,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
36447
36451
return createTupleType(types, flags, readonly, names);
36448
36452
}
36449
36453
36454
+ // Return the rest type at the given position, transforming `any[]` into just `any`. We do this because
36455
+ // in signatures we want `any[]` in a rest position to be compatible with anything, but `any[]` isn't
36456
+ // assignable to tuple types with required elements.
36457
+ function getRestOrAnyTypeAtPosition(source: Signature, pos: number): Type {
36458
+ const restType = getRestTypeAtPosition(source, pos);
36459
+ const elementType = restType && getElementTypeOfArrayType(restType);
36460
+ return elementType && isTypeAny(elementType) ? anyType : restType;
36461
+ }
36462
+
36450
36463
// Return the number of parameters in a signature. The rest parameter, if present, counts as one
36451
36464
// parameter. For example, the parameter count of (x: number, y: number, ...z: string[]) is 3 and
36452
36465
// the parameter count of (x: number, ...args: [number, ...string[], boolean])) is also 3. In the
@@ -36510,7 +36523,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
36510
36523
if (signatureHasRestParameter(signature)) {
36511
36524
const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]);
36512
36525
if (!isTupleType(restType)) {
36513
- return restType;
36526
+ return isTypeAny(restType) ? anyArrayType : restType;
36514
36527
}
36515
36528
if (restType.target.hasRestElement) {
36516
36529
return sliceTupleType(restType, restType.target.fixedLength);
@@ -40510,7 +40523,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
40510
40523
const objectIndexType = isGenericMappedType(objectType) && getMappedTypeNameTypeKind(objectType) === MappedTypeNameTypeKind.Remapping
40511
40524
? getIndexTypeForMappedType(objectType, IndexFlags.None)
40512
40525
: getIndexType(objectType, IndexFlags.None);
40513
- if (isTypeAssignableTo(indexType, objectIndexType)) {
40526
+ const hasNumberIndexInfo = !!getIndexInfoOfType(objectType, numberType);
40527
+ if (everyType(indexType, t => isTypeAssignableTo(t, objectIndexType) || hasNumberIndexInfo && isApplicableIndexType(t, numberType))) {
40514
40528
if (
40515
40529
accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) &&
40516
40530
getObjectFlags(objectType) & ObjectFlags.Mapped && getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.IncludeReadonly
@@ -40519,16 +40533,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
40519
40533
}
40520
40534
return type;
40521
40535
}
40522
- // Check if we're indexing with a numeric type and if either object or index types
40523
- // is a generic type with a constraint that has a numeric index signature.
40524
- const apparentObjectType = getApparentType(objectType);
40525
- if (getIndexInfoOfType(apparentObjectType, numberType) && isTypeAssignableToKind(indexType, TypeFlags.NumberLike)) {
40526
- return type;
40527
- }
40528
40536
if (isGenericObjectType(objectType)) {
40529
40537
const propertyName = getPropertyNameFromIndex(indexType, accessNode);
40530
40538
if (propertyName) {
40531
- const propertySymbol = forEachType(apparentObjectType , t => getPropertyOfType(t, propertyName));
40539
+ const propertySymbol = forEachType(getApparentType(objectType) , t => getPropertyOfType(t, propertyName));
40532
40540
if (propertySymbol && getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.NonPublicAccessibilityModifier) {
40533
40541
error(accessNode, Diagnostics.Private_or_protected_member_0_cannot_be_accessed_on_a_type_parameter, unescapeLeadingUnderscores(propertyName));
40534
40542
return errorType;
0 commit comments