@@ -4514,22 +4514,27 @@ namespace ts {
45144514 // present (aka the tuple element property). This call also checks that the parentType is in
45154515 // fact an iterable or array (depending on target language).
45164516 const elementType = checkIteratedTypeOrElementType(parentType, pattern, /*allowStringInput*/ false, /*allowAsyncIterables*/ false);
4517+ const index = pattern.elements.indexOf(declaration);
45174518 if (declaration.dotDotDotToken) {
4518- // Rest element has an array type with the same element type as the parent type
4519- type = createArrayType(elementType);
4519+ // If the parent is a tuple type, the rest element has an array type with a union of the
4520+ // remaining tuple element types. Otherwise, the rest element has an array type with same
4521+ // element type as the parent type.
4522+ type = isTupleType(parentType) ?
4523+ getArrayLiteralType((parentType.typeArguments || emptyArray).slice(index, getTypeReferenceArity(parentType))) :
4524+ createArrayType(elementType);
45204525 }
45214526 else {
45224527 // Use specific property type when parent is a tuple or numeric index type when parent is an array
4523- const propName = "" + pattern.elements.indexOf(declaration);
4524- type = isTupleLikeType(parentType)
4525- ? getTypeOfPropertyOfType (parentType, propName as __String)
4526- : elementType;
4528+ const index = pattern.elements.indexOf(declaration);
4529+ type = isTupleLikeType(parentType) ?
4530+ getTupleElementType (parentType, index) || declaration.initializer && checkDeclarationInitializer(declaration) :
4531+ elementType;
45274532 if (!type) {
45284533 if (isTupleType(parentType)) {
45294534 error(declaration, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(parentType), getTypeReferenceArity(<TypeReference>parentType), pattern.elements.length);
45304535 }
45314536 else {
4532- error(declaration, Diagnostics.Type_0_has_no_property_1, typeToString(parentType), propName );
4537+ error(declaration, Diagnostics.Type_0_has_no_property_1, typeToString(parentType), "" + index );
45334538 }
45344539 return errorType;
45354540 }
@@ -4800,7 +4805,7 @@ namespace ts {
48004805 // pattern. Otherwise, it is the type any.
48014806 function getTypeFromBindingElement(element: BindingElement, includePatternInType?: boolean, reportErrors?: boolean): Type {
48024807 if (element.initializer) {
4803- return checkDeclarationInitializer(element);
4808+ return addOptionality( checkDeclarationInitializer(element) );
48044809 }
48054810 if (isBindingPattern(element.name)) {
48064811 return getTypeFromBindingPattern(element.name, includePatternInType, reportErrors);
@@ -4848,12 +4853,13 @@ namespace ts {
48484853 function getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type {
48494854 const elements = pattern.elements;
48504855 const lastElement = lastOrUndefined(elements);
4851- if (!lastElement || (!isOmittedExpression(lastElement) && lastElement.dotDotDotToken)) {
4856+ const hasRestElement = !!(lastElement && lastElement.kind === SyntaxKind.BindingElement && lastElement.dotDotDotToken);
4857+ if (elements.length === 0 || elements.length === 1 && hasRestElement) {
48524858 return languageVersion >= ScriptTarget.ES2015 ? createIterableType(anyType) : anyArrayType;
48534859 }
4854- // If the pattern has at least one element, and no rest element, then it should imply a tuple type.
48554860 const elementTypes = map(elements, e => isOmittedExpression(e) ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors));
4856- let result = <TypeReference>createTupleType(elementTypes);
4861+ const minLength = findLastIndex(elements, e => !isOmittedExpression(e) && !hasDefaultValue(e), elements.length - (hasRestElement ? 2 : 1)) + 1;
4862+ let result = <TypeReference>createTupleType(elementTypes, minLength, hasRestElement);
48574863 if (includePatternInType) {
48584864 result = cloneTypeReference(result);
48594865 result.pattern = pattern;
@@ -12076,6 +12082,12 @@ namespace ts {
1207612082 return isTupleType(type) || !!getPropertyOfType(type, "0" as __String);
1207712083 }
1207812084
12085+ function getTupleElementType(type: Type, index: number) {
12086+ return isTupleType(type) ?
12087+ index < getLengthOfTupleType(type) ? type.typeArguments![index] : getRestTypeOfTupleType(type) :
12088+ getTypeOfPropertyOfType(type, "" + index as __String);
12089+ }
12090+
1207912091 function isNeitherUnitTypeNorNever(type: Type): boolean {
1208012092 return !(type.flags & (TypeFlags.Unit | TypeFlags.Never));
1208112093 }
@@ -13471,7 +13483,7 @@ namespace ts {
1347113483 }
1347213484
1347313485 function getTypeOfDestructuredArrayElement(type: Type, index: number) {
13474- return isTupleLikeType(type) && getTypeOfPropertyOfType (type, "" + index as __String ) ||
13486+ return isTupleLikeType(type) && getTupleElementType (type, index) ||
1347513487 checkIteratedTypeOrElementType(type, /*errorNode*/ undefined, /*allowStringInput*/ false, /*allowAsyncIterables*/ false) ||
1347613488 errorType;
1347713489 }
@@ -15993,11 +16005,12 @@ namespace ts {
1599316005
1599416006 function checkArrayLiteral(node: ArrayLiteralExpression, checkMode: CheckMode | undefined): Type {
1599516007 const elements = node.elements;
16008+ const elementCount = elements.length;
1599616009 let hasNonEndingSpreadElement = false;
1599716010 const elementTypes: Type[] = [];
1599816011 const inDestructuringPattern = isAssignmentTarget(node);
1599916012 const contextualType = getApparentTypeOfContextualType(node);
16000- for (let index = 0; index < elements.length ; index++) {
16013+ for (let index = 0; index < elementCount ; index++) {
1600116014 const e = elements[index];
1600216015 if (inDestructuringPattern && e.kind === SyntaxKind.SpreadElement) {
1600316016 // Given the following situation:
@@ -16024,41 +16037,48 @@ namespace ts {
1602416037 const type = checkExpressionForMutableLocation(e, checkMode, elementContextualType);
1602516038 elementTypes.push(type);
1602616039 }
16027- hasNonEndingSpreadElement = hasNonEndingSpreadElement || (index < elements.length - 1 && e.kind === SyntaxKind.SpreadElement);
16040+ if (index < elementCount - 1 && e.kind === SyntaxKind.SpreadElement) {
16041+ hasNonEndingSpreadElement = true;
16042+ }
1602816043 }
1602916044 if (!hasNonEndingSpreadElement) {
16045+ const hasRestElement = elementCount > 0 && elements[elementCount - 1].kind === SyntaxKind.SpreadElement;
16046+ const minLength = elementCount - (hasRestElement ? 1 : 0);
1603016047 // If array literal is actually a destructuring pattern, mark it as an implied type. We do this such
1603116048 // that we get the same behavior for "var [x, y] = []" and "[x, y] = []".
16032- if (inDestructuringPattern && elementTypes.length ) {
16033- const type = cloneTypeReference(<TypeReference>createTupleType(elementTypes));
16049+ if (inDestructuringPattern && minLength > 0 ) {
16050+ const type = cloneTypeReference(<TypeReference>createTupleType(elementTypes, minLength, hasRestElement ));
1603416051 type.pattern = node;
1603516052 return type;
1603616053 }
1603716054 if (contextualType && contextualTypeIsTupleLikeType(contextualType)) {
1603816055 const pattern = contextualType.pattern;
1603916056 // If array literal is contextually typed by a binding pattern or an assignment pattern, pad the resulting
1604016057 // tuple type with the corresponding binding or assignment element types to make the lengths equal.
16041- if (pattern && (pattern.kind === SyntaxKind.ArrayBindingPattern || pattern.kind === SyntaxKind.ArrayLiteralExpression)) {
16058+ if (!hasRestElement && pattern && (pattern.kind === SyntaxKind.ArrayBindingPattern || pattern.kind === SyntaxKind.ArrayLiteralExpression)) {
1604216059 const patternElements = (<BindingPattern | ArrayLiteralExpression>pattern).elements;
16043- for (let i = elementTypes.length ; i < patternElements.length; i++) {
16044- const patternElement = patternElements[i];
16045- if (hasDefaultValue(patternElement )) {
16060+ for (let i = elementCount ; i < patternElements.length; i++) {
16061+ const e = patternElements[i];
16062+ if (hasDefaultValue(e )) {
1604616063 elementTypes.push((<TypeReference>contextualType).typeArguments![i]);
1604716064 }
16048- else {
16049- if (patternElement .kind !== SyntaxKind.OmittedExpression) {
16050- error(patternElement , Diagnostics.Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value);
16065+ else if (i < patternElements.length - 1 || !(e.kind === SyntaxKind.BindingElement && (<BindingElement>e).dotDotDotToken || e.kind === SyntaxKind.SpreadElement)) {
16066+ if (e .kind !== SyntaxKind.OmittedExpression) {
16067+ error(e , Diagnostics.Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value);
1605116068 }
1605216069 elementTypes.push(strictNullChecks ? implicitNeverType : undefinedWideningType);
1605316070 }
1605416071 }
1605516072 }
16056- const hasSpreadElement = elements.length > 0 && elements[elements.length - 1].kind === SyntaxKind.SpreadElement;
16057- return createTupleType(elementTypes, elementTypes.length - (hasSpreadElement ? 1 : 0), hasSpreadElement);
16073+ return createTupleType(elementTypes, minLength, hasRestElement);
1605816074 }
1605916075 }
16076+ return getArrayLiteralType(elementTypes, UnionReduction.Subtype);
16077+ }
16078+
16079+ function getArrayLiteralType(elementTypes: Type[], unionReduction = UnionReduction.Literal) {
1606016080 return createArrayType(elementTypes.length ?
16061- getUnionType(elementTypes, UnionReduction.Subtype ) :
16081+ getUnionType(elementTypes, unionReduction ) :
1606216082 strictNullChecks ? implicitNeverType : undefinedWideningType);
1606316083 }
1606416084
@@ -20418,24 +20438,20 @@ namespace ts {
2041820438 if (element.kind !== SyntaxKind.OmittedExpression) {
2041920439 if (element.kind !== SyntaxKind.SpreadElement) {
2042020440 const propName = "" + elementIndex as __String;
20421- const type = isTypeAny(sourceType)
20422- ? sourceType
20423- : isTupleLikeType(sourceType)
20424- ? getTypeOfPropertyOfType(sourceType, propName)
20425- : elementType;
20441+ const type = isTypeAny(sourceType) ? sourceType :
20442+ isTupleLikeType(sourceType) ? getTupleElementType(sourceType, elementIndex) :
20443+ elementType;
2042620444 if (type) {
2042720445 return checkDestructuringAssignment(element, type, checkMode);
2042820446 }
20447+ // We still need to check element expression here because we may need to set appropriate flag on the expression
20448+ // such as NodeCheckFlags.LexicalThis on "this"expression.
20449+ checkExpression(element);
20450+ if (isTupleType(sourceType)) {
20451+ error(element, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(sourceType), getTypeReferenceArity(<TypeReference>sourceType), elements.length);
20452+ }
2042920453 else {
20430- // We still need to check element expression here because we may need to set appropriate flag on the expression
20431- // such as NodeCheckFlags.LexicalThis on "this"expression.
20432- checkExpression(element);
20433- if (isTupleType(sourceType)) {
20434- error(element, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(sourceType), getTypeReferenceArity(<TypeReference>sourceType), elements.length);
20435- }
20436- else {
20437- error(element, Diagnostics.Type_0_has_no_property_1, typeToString(sourceType), propName as string);
20438- }
20454+ error(element, Diagnostics.Type_0_has_no_property_1, typeToString(sourceType), propName as string);
2043920455 }
2044020456 }
2044120457 else {
@@ -20449,7 +20465,10 @@ namespace ts {
2044920465 }
2045020466 else {
2045120467 checkGrammarForDisallowedTrailingComma(node.elements, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma);
20452- return checkDestructuringAssignment(restExpression, createArrayType(elementType), checkMode);
20468+ const type = isTupleType(sourceType) ?
20469+ getArrayLiteralType((sourceType.typeArguments || emptyArray).slice(elementIndex, getTypeReferenceArity(sourceType))) :
20470+ createArrayType(elementType);
20471+ return checkDestructuringAssignment(restExpression, type, checkMode);
2045320472 }
2045420473 }
2045520474 }
0 commit comments