@@ -12336,18 +12336,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
12336
12336
}
12337
12337
const elementTypes = map(elements, e => isOmittedExpression(e) ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors));
12338
12338
12339
- let minLength: number;
12340
- if (includePatternInType) {
12341
- // For contextual typing, be more conservative about tuple length to avoid inference differences
12342
- // based purely on binding patterns. Find the minimum meaningful length.
12343
- const lastRequiredIndex = findLastIndex(elements, e => !(e === restElement || hasDefaultValue(e)), elements.length - 1);
12344
- minLength = lastRequiredIndex >= 0 ? Math.min(lastRequiredIndex + 1, 2) : 0;
12345
- } else {
12346
- // For regular typing, use the existing logic
12347
- minLength = findLastIndex(elements, e => !(e === restElement || isOmittedExpression(e) || hasDefaultValue(e)), elements.length - 1) + 1;
12339
+ // For contextual typing, ensure both [, , t] and [, s, ] produce the same contextual type [any, any, any]
12340
+ // by extending shorter tuples to at least 3 elements when constructing contextual types
12341
+ if (includePatternInType && !restElement && elementTypes.length < 3) {
12342
+ while (elementTypes.length < 3) {
12343
+ elementTypes.push(anyType);
12344
+ }
12348
12345
}
12349
12346
12350
- const elementFlags = map(elements, (e, i) => e === restElement ? ElementFlags.Rest : i >= minLength ? ElementFlags.Optional : ElementFlags.Required);
12347
+ const minLength = findLastIndex(elements, e => !(e === restElement || isOmittedExpression(e) || hasDefaultValue(e)), elements.length - 1) + 1;
12348
+ const elementFlags = map(elementTypes, (_, i) => {
12349
+ if (i < elements.length) {
12350
+ const e = elements[i];
12351
+ return e === restElement ? ElementFlags.Rest : i >= minLength ? ElementFlags.Optional : ElementFlags.Required;
12352
+ } else {
12353
+ // Added elements for contextual typing should be optional
12354
+ return ElementFlags.Optional;
12355
+ }
12356
+ });
12351
12357
let result = createTupleType(elementTypes, elementFlags) as TypeReference;
12352
12358
if (includePatternInType) {
12353
12359
result = cloneTypeReference(result);
@@ -31876,22 +31882,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
31876
31882
}
31877
31883
}
31878
31884
31879
- function getContextualTypeForBindingElement(declaration: BindingElement, contextFlags: ContextFlags | undefined): Type | undefined {
31880
- const parent = declaration.parent.parent;
31881
- const name = declaration.propertyName || declaration.name;
31882
- const parentType = getContextualTypeForVariableLikeDeclaration(parent, contextFlags) ||
31883
- parent.kind !== SyntaxKind.BindingElement && parent.initializer && checkDeclarationInitializer(parent, declaration.dotDotDotToken ? CheckMode.RestBindingElement : CheckMode.Normal);
31884
- if (!parentType || isBindingPattern(name) || isComputedNonLiteralName(name)) return undefined;
31885
- if (parent.name.kind === SyntaxKind.ArrayBindingPattern) {
31886
- const index = indexOfNode(declaration.parent.elements, declaration);
31887
- if (index < 0) return undefined;
31888
- return getContextualTypeForElementExpression(parentType, index);
31889
- }
31890
- const nameType = getLiteralTypeFromPropertyName(name);
31891
- if (isTypeUsableAsPropertyName(nameType)) {
31892
- const text = getPropertyNameFromType(nameType);
31893
- return getTypeOfPropertyOfType(parentType, text);
31894
- }
31885
+ function getContextualTypeForBindingElement(declaration: BindingElement, contextFlags: ContextFlags | undefined): Type | undefined {
31886
+ const parent = declaration.parent.parent;
31887
+ const name = declaration.propertyName || declaration.name;
31888
+ const parentType = getContextualTypeForVariableLikeDeclaration(parent, contextFlags) ||
31889
+ parent.kind !== SyntaxKind.BindingElement && parent.initializer && checkDeclarationInitializer(parent, declaration.dotDotDotToken ? CheckMode.RestBindingElement : CheckMode.Normal);
31890
+ if (!parentType || isBindingPattern(name) || isComputedNonLiteralName(name)) return undefined;
31891
+ if (parent.name.kind === SyntaxKind.ArrayBindingPattern) {
31892
+ const index = indexOfNode(declaration.parent.elements, declaration);
31893
+ if (index < 0) return undefined;
31894
+ return getContextualTypeForElementExpression(parentType, index);
31895
+ }
31896
+ const nameType = getLiteralTypeFromPropertyName(name);
31897
+ if (isTypeUsableAsPropertyName(nameType)) {
31898
+ const text = getPropertyNameFromType(nameType);
31899
+ return getTypeOfPropertyOfType(parentType, text);
31900
+ }
31895
31901
}
31896
31902
31897
31903
function getContextualTypeForStaticPropertyDeclaration(declaration: PropertyDeclaration, contextFlags: ContextFlags | undefined): Type | undefined {
@@ -31908,18 +31914,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
31908
31914
// the contextual type of an initializer expression is the type implied by the binding pattern.
31909
31915
// Otherwise, in a binding pattern inside a variable or parameter declaration,
31910
31916
// the contextual type of an initializer expression is the type annotation of the containing declaration, if present.
31911
- function getContextualTypeForInitializerExpression(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined {
31912
- const declaration = node.parent as VariableLikeDeclaration;
31913
- if (hasInitializer(declaration) && node === declaration.initializer) {
31914
- const result = getContextualTypeForVariableLikeDeclaration(declaration, contextFlags);
31915
- if (result) {
31916
- return result;
31917
- }
31918
- if (!(contextFlags! & ContextFlags.SkipBindingPatterns) && isBindingPattern(declaration.name) && declaration.name.elements.length > 0) {
31919
- return getTypeFromBindingPattern(declaration.name, /*includePatternInType*/ true, /*reportErrors*/ false);
31920
- }
31921
- }
31922
- return undefined;
31917
+ function getContextualTypeForInitializerExpression(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined {
31918
+ const declaration = node.parent as VariableLikeDeclaration;
31919
+ if (hasInitializer(declaration) && node === declaration.initializer) {
31920
+ const result = getContextualTypeForVariableLikeDeclaration(declaration, contextFlags);
31921
+ if (result) {
31922
+ return result;
31923
+ }
31924
+ if (!(contextFlags! & ContextFlags.SkipBindingPatterns) && isBindingPattern(declaration.name) && declaration.name.elements.length > 0) {
31925
+ return getTypeFromBindingPattern(declaration.name, /*includePatternInType*/ true, /*reportErrors*/ false);
31926
+ }
31927
+ }
31928
+ return undefined;
31923
31929
}
31924
31930
31925
31931
function getContextualTypeForReturnExpression(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined {
0 commit comments