Skip to content
51 changes: 34 additions & 17 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12327,23 +12327,40 @@
}

// Return the type implied by an array binding pattern
function getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type {
const elements = pattern.elements;
const lastElement = lastOrUndefined(elements);
const restElement = lastElement && lastElement.kind === SyntaxKind.BindingElement && lastElement.dotDotDotToken ? lastElement : undefined;
if (elements.length === 0 || elements.length === 1 && restElement) {
return languageVersion >= ScriptTarget.ES2015 ? createIterableType(anyType) : anyArrayType;
}
const elementTypes = map(elements, e => isOmittedExpression(e) ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors));
const minLength = findLastIndex(elements, e => !(e === restElement || isOmittedExpression(e) || hasDefaultValue(e)), elements.length - 1) + 1;
const elementFlags = map(elements, (e, i) => e === restElement ? ElementFlags.Rest : i >= minLength ? ElementFlags.Optional : ElementFlags.Required);
let result = createTupleType(elementTypes, elementFlags) as TypeReference;
if (includePatternInType) {
result = cloneTypeReference(result);
result.pattern = pattern;
result.objectFlags |= ObjectFlags.ContainsObjectOrArrayLiteral;
}
return result;
function getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type {
const elements = pattern.elements;
const lastElement = lastOrUndefined(elements);
const restElement = lastElement && lastElement.kind === SyntaxKind.BindingElement && lastElement.dotDotDotToken ? lastElement : undefined;
if (elements.length === 0 || elements.length === 1 && restElement) {
return languageVersion >= ScriptTarget.ES2015 ? createIterableType(anyType) : anyArrayType;
}
const elementTypes = map(elements, e => isOmittedExpression(e) ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors));

Check failure on line 12338 in src/compiler/checker.ts

View workflow job for this annotation

GitHub Actions / copilot

'elementTypes' is never reassigned. Use 'const' instead
// For contextual typing, ensure both [, , t] and [, s, ] produce the same contextual type [any, any, any]
// by extending shorter tuples to at least 3 elements when constructing contextual types
if (includePatternInType && !restElement && elementTypes.length < 3) {
while (elementTypes.length < 3) {
elementTypes.push(anyType);
}
}

const minLength = findLastIndex(elements, e => !(e === restElement || isOmittedExpression(e) || hasDefaultValue(e)), elements.length - 1) + 1;
const elementFlags = map(elementTypes, (_, i) => {
if (i < elements.length) {
const e = elements[i];
return e === restElement ? ElementFlags.Rest : i >= minLength ? ElementFlags.Optional : ElementFlags.Required;
} else {
// Added elements for contextual typing should be optional
return ElementFlags.Optional;
}
});
let result = createTupleType(elementTypes, elementFlags) as TypeReference;
if (includePatternInType) {
result = cloneTypeReference(result);
result.pattern = pattern;
result.objectFlags |= ObjectFlags.ContainsObjectOrArrayLiteral;
}
return result;
}

// Return the type implied by a binding pattern. This is the type implied purely by the binding pattern itself
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// @strict: true

type DataType = 'a' | 'b';
declare function foo<T extends { dataType: DataType }>(template: T): [T, any, any];

// These should behave the same - both should allow excess properties
const [, , t] = foo({ dataType: 'a', day: 0 });
const [, s, ] = foo({ dataType: 'a', day: 0 });