Skip to content

Commit 2e52498

Browse files
committed
Remove logic that pads array literals contextually typed by tuple types
1 parent 2af8ac7 commit 2e52498

File tree

1 file changed

+19
-31
lines changed

1 file changed

+19
-31
lines changed

src/compiler/checker.ts

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,7 @@ namespace ts {
722722
NoIndexSignatures = 1 << 0,
723723
Writing = 1 << 1,
724724
CacheSymbol = 1 << 2,
725+
NoTupleBoundsCheck = 1 << 3,
725726
}
726727

727728
const enum CallbackCheck {
@@ -5115,21 +5116,25 @@ namespace ts {
51155116
}
51165117
else if (isArrayLikeType(parentType)) {
51175118
const indexType = getLiteralType(index);
5118-
const declaredType = getConstraintForLocation(getIndexedAccessType(parentType, indexType, declaration.name), declaration.name);
5119+
const accessFlags = hasDefaultValue(declaration) ? AccessFlags.NoTupleBoundsCheck : 0;
5120+
const declaredType = getConstraintForLocation(getIndexedAccessTypeOrUndefined(parentType, indexType, declaration.name, accessFlags) || errorType, declaration.name);
51195121
type = getFlowTypeOfDestructuring(declaration, declaredType);
51205122
}
51215123
else {
51225124
type = elementType;
51235125
}
51245126
}
5125-
// In strict null checking mode, if a default value of a non-undefined type is specified, remove
5126-
// undefined from the final type.
5127-
if (strictNullChecks && declaration.initializer && !(getFalsyFlags(checkDeclarationInitializer(declaration)) & TypeFlags.Undefined)) {
5128-
type = getTypeWithFacts(type, TypeFacts.NEUndefined);
5127+
if (!declaration.initializer) {
5128+
return type;
51295129
}
5130-
return declaration.initializer && !getEffectiveTypeAnnotationNode(walkUpBindingElementsAndPatterns(declaration)) ?
5131-
getUnionType([type, checkDeclarationInitializer(declaration)], UnionReduction.Subtype) :
5132-
type;
5130+
if (getEffectiveTypeAnnotationNode(walkUpBindingElementsAndPatterns(declaration))) {
5131+
// In strict null checking mode, if a default value of a non-undefined type is specified, remove
5132+
// undefined from the final type.
5133+
return strictNullChecks && !(getFalsyFlags(checkDeclarationInitializer(declaration)) & TypeFlags.Undefined) ?
5134+
getTypeWithFacts(type, TypeFacts.NEUndefined) :
5135+
type;
5136+
}
5137+
return getUnionType([getTypeWithFacts(type, TypeFacts.NEUndefined), checkDeclarationInitializer(declaration)], UnionReduction.Subtype);
51335138
}
51345139

51355140
function getTypeForDeclarationFromJSDocComment(declaration: Node) {
@@ -10131,7 +10136,7 @@ namespace ts {
1013110136
propType;
1013210137
}
1013310138
if (everyType(objectType, isTupleType) && isNumericLiteralName(propName) && +propName >= 0) {
10134-
if (accessNode && everyType(objectType, t => !(<TupleTypeReference>t).target.hasRestElement)) {
10139+
if (accessNode && everyType(objectType, t => !(<TupleTypeReference>t).target.hasRestElement) && !(accessFlags & AccessFlags.NoTupleBoundsCheck)) {
1013510140
const indexNode = getIndexNodeForAccessExpression(accessNode);
1013610141
if (isTupleType(objectType)) {
1013710142
error(indexNode, Diagnostics.Tuple_type_0_of_length_1_has_no_element_at_index_2,
@@ -19196,26 +19201,7 @@ namespace ts {
1919619201
function getArrayLiteralTupleTypeIfApplicable(elementTypes: Type[], contextualType: Type | undefined, hasRestElement: boolean, elementCount = elementTypes.length, readonly = false) {
1919719202
// Infer a tuple type when the contextual type is or contains a tuple-like type
1919819203
if (readonly || (contextualType && forEachType(contextualType, isTupleLikeType))) {
19199-
const minLength = elementCount - (hasRestElement ? 1 : 0);
19200-
const pattern = contextualType && contextualType.pattern;
19201-
// If array literal is contextually typed by a binding pattern or an assignment pattern, pad the resulting
19202-
// tuple type with the corresponding binding or assignment element types to make the lengths equal.
19203-
if (!hasRestElement && pattern && (pattern.kind === SyntaxKind.ArrayBindingPattern || pattern.kind === SyntaxKind.ArrayLiteralExpression)) {
19204-
const patternElements = (<BindingPattern | ArrayLiteralExpression>pattern).elements;
19205-
for (let i = elementCount; i < patternElements.length; i++) {
19206-
const e = patternElements[i];
19207-
if (hasDefaultValue(e)) {
19208-
elementTypes.push((<TypeReference>contextualType).typeArguments![i]);
19209-
}
19210-
else if (i < patternElements.length - 1 || !(e.kind === SyntaxKind.BindingElement && (<BindingElement>e).dotDotDotToken || e.kind === SyntaxKind.SpreadElement)) {
19211-
if (e.kind !== SyntaxKind.OmittedExpression) {
19212-
error(e, Diagnostics.Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value);
19213-
}
19214-
elementTypes.push(strictNullChecks ? implicitNeverType : undefinedWideningType);
19215-
}
19216-
}
19217-
}
19218-
return createTupleType(elementTypes, minLength, hasRestElement, readonly);
19204+
return createTupleType(elementTypes, elementCount - (hasRestElement ? 1 : 0), hasRestElement, readonly);
1921919205
}
1922019206
}
1922119207

@@ -23655,8 +23641,10 @@ namespace ts {
2365523641
if (isArrayLikeType(sourceType)) {
2365623642
// We create a synthetic expression so that getIndexedAccessType doesn't get confused
2365723643
// when the element is a SyntaxKind.ElementAccessExpression.
23658-
const elementType = getIndexedAccessType(sourceType, indexType, createSyntheticExpression(element, indexType));
23659-
const type = getFlowTypeOfDestructuring(element, elementType);
23644+
const accessFlags = hasDefaultValue(element) ? AccessFlags.NoTupleBoundsCheck : 0;
23645+
const elementType = getIndexedAccessTypeOrUndefined(sourceType, indexType, createSyntheticExpression(element, indexType), accessFlags) || errorType;
23646+
const assignedType = hasDefaultValue(element) ? getTypeWithFacts(elementType, TypeFacts.NEUndefined) : elementType;
23647+
const type = getFlowTypeOfDestructuring(element, assignedType);
2366023648
return checkDestructuringAssignment(element, type, checkMode);
2366123649
}
2366223650
return checkDestructuringAssignment(element, elementType, checkMode);

0 commit comments

Comments
 (0)