@@ -31857,10 +31857,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3185731857 const parentType = getContextualTypeForVariableLikeDeclaration(parent, contextFlags) ||
3185831858 parent.kind !== SyntaxKind.BindingElement && parent.initializer && checkDeclarationInitializer(parent, declaration.dotDotDotToken ? CheckMode.RestBindingElement : CheckMode.Normal);
3185931859 if (!parentType || isBindingPattern(name) || isComputedNonLiteralName(name)) return undefined;
31860- if (parent.name.kind === SyntaxKind.ArrayBindingPattern) {
31861- const index = indexOfNode(declaration.parent.elements, declaration);
31862- if (index < 0) return undefined;
31863- return getContextualTypeForElementExpression(parentType, index, declaration.parent.elements.length);
31860+ if (parent.name.kind === SyntaxKind.ArrayBindingPattern) {
31861+ const index = indexOfNode(declaration.parent.elements, declaration);
31862+ if (index < 0) return undefined;
31863+ return getContextualTypeForElementExpression(parentType, index, declaration.parent.elements.length);
3186431864 }
3186531865 const nameType = getLiteralTypeFromPropertyName(name);
3186631866 if (isTypeUsableAsPropertyName(nameType)) {
@@ -32391,25 +32391,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3239132391 return { first, last };
3239232392 }
3239332393
32394- function getContextualTypeForElementExpression(type: Type | undefined, index: number, length?: number, firstSpreadIndex?: number, lastSpreadIndex?: number): Type | undefined {
32395- return type && mapType(type, t => {
32396- if (isTupleType(t)) {
32397- // If index is before any spread element and within the fixed part of the contextual tuple type, return
32398- // the type of the contextual tuple element.
32399- if ((firstSpreadIndex === undefined || index < firstSpreadIndex) && index < t.target.fixedLength) {
32400- return removeMissingType(getTypeArguments(t)[index], !!(t.target.elementFlags[index] && ElementFlags.Optional));
32401- }
32402- // When the length is known and the index is after all spread elements we compute the offset from the element
32403- // to the end and the number of ending fixed elements in the contextual tuple type.
32404- const offset = length !== undefined && (lastSpreadIndex === undefined || index > lastSpreadIndex) ? length - index : 0;
32405- const fixedEndLength = offset > 0 && (t.target.combinedFlags & ElementFlags.Variable) ? getEndElementCount(t.target, ElementFlags.Fixed) : 0;
32406- // If the offset is within the ending fixed part of the contextual tuple type, return the type of the contextual
32407- // tuple element.
32408- if (offset > 0 && offset <= fixedEndLength) {
32409- return getTypeArguments(t)[getTypeReferenceArity(t) - offset];
32410- }
32411- // Return a union of the possible contextual element types with no subtype reduction.
32412- return getElementTypeOfSliceOfTupleType(t, firstSpreadIndex === undefined ? t.target.fixedLength : Math.min(t.target.fixedLength, firstSpreadIndex), length === undefined || lastSpreadIndex === undefined ? fixedEndLength : Math.min(fixedEndLength, length - lastSpreadIndex), /*writing*/ false, /*noReductions*/ true);
32394+ function getContextualTypeForElementExpression(type: Type | undefined, index: number, length?: number, firstSpreadIndex?: number, lastSpreadIndex?: number): Type | undefined {
32395+ return type && mapType(type, t => {
32396+ if (isTupleType(t)) {
32397+ // If index is before any spread element and within the fixed part of the contextual tuple type, return
32398+ // the type of the contextual tuple element.
32399+ if ((firstSpreadIndex === undefined || index < firstSpreadIndex) && index < t.target.fixedLength) {
32400+ return removeMissingType(getTypeArguments(t)[index], !!(t.target.elementFlags[index] && ElementFlags.Optional));
32401+ }
32402+ // When the length is known and the index is after all spread elements we compute the offset from the element
32403+ // to the end and the number of ending fixed elements in the contextual tuple type.
32404+ const offset = length !== undefined && (lastSpreadIndex === undefined || index > lastSpreadIndex) ? length - index : 0;
32405+ const fixedEndLength = offset > 0 && (t.target.combinedFlags & ElementFlags.Variable) ? getEndElementCount(t.target, ElementFlags.Fixed) : 0;
32406+ // If the offset is within the ending fixed part of the contextual tuple type, return the type of the contextual
32407+ // tuple element.
32408+ if (offset > 0 && offset <= fixedEndLength) {
32409+ return getTypeArguments(t)[getTypeReferenceArity(t) - offset];
32410+ }
32411+ // Return a union of the possible contextual element types with no subtype reduction.
32412+ return getElementTypeOfSliceOfTupleType(t, firstSpreadIndex === undefined ? t.target.fixedLength : Math.min(t.target.fixedLength, firstSpreadIndex), length === undefined || lastSpreadIndex === undefined ? fixedEndLength : Math.min(fixedEndLength, length - lastSpreadIndex), /*writing*/ false, /*noReductions*/ true);
3241332413 }
3241432414 // If element index is known and a contextual property with that name exists, return it. Otherwise return the
3241532415 // iterated or element type of the contextual type.
@@ -36027,6 +36027,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3602736027 return skipOuterExpressions(argument, flags);
3602836028 }
3602936029
36030+ function isCallInLastTupleElementDestructuring(node: CallLikeExpression): boolean {
36031+ // Check if this call expression is used as initializer in a variable declaration with array destructuring
36032+ const parent = node.parent;
36033+ if (parent && isVariableDeclaration(parent) && parent.initializer === node && isArrayBindingPattern(parent.name)) {
36034+ const elements = parent.name.elements;
36035+ // Check if the destructuring pattern accesses the last element
36036+ // (i.e., the last non-omitted element is at the end of the pattern)
36037+ for (let i = elements.length - 1; i >= 0; i--) {
36038+ if (!isOmittedExpression(elements[i])) {
36039+ // If the last non-omitted element is at the last position, it's accessing the last tuple element
36040+ return i === elements.length - 1;
36041+ }
36042+ }
36043+ }
36044+ return false;
36045+ }
36046+
3603036047 function getSignatureApplicabilityError(
3603136048 node: CallLikeExpression,
3603236049 args: readonly Expression[],
@@ -36069,7 +36086,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3606936086 // If one or more arguments are still excluded (as indicated by CheckMode.SkipContextSensitive),
3607036087 // we obtain the regular type of any object literal arguments because we may not have inferred complete
3607136088 // parameter types yet and therefore excess property checks may yield false positives (see #17041).
36072- const checkArgType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(argType) : argType;
36089+ // Also skip fresh literal checking when the call is in last tuple element destructuring context
36090+ // to prevent incorrect excess property errors (see #41548).
36091+ const shouldSkipFreshness = (checkMode & CheckMode.SkipContextSensitive) ||
36092+ (isCallExpression(node) && isCallInLastTupleElementDestructuring(node));
36093+ const checkArgType = shouldSkipFreshness ? getRegularTypeOfObjectLiteral(argType) : argType;
3607336094 const effectiveCheckArgumentNode = getEffectiveCheckNode(arg);
3607436095 if (!checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? effectiveCheckArgumentNode : undefined, effectiveCheckArgumentNode, headMessage, containingMessageChain, errorOutputContainer)) {
3607536096 Debug.assert(!reportErrors || !!errorOutputContainer.errors, "parameter should have errors when reporting errors");
0 commit comments