@@ -83,6 +83,7 @@ namespace ts {
8383 getShorthandAssignmentValueSymbol,
8484 getExportSpecifierLocalTargetSymbol,
8585 getTypeAtLocation: getTypeOfNode,
86+ getPropertySymbolOfDestructuringAssignment,
8687 typeToString,
8788 getSymbolDisplayBuilder,
8889 symbolToString,
@@ -11810,39 +11811,43 @@ namespace ts {
1181011811 function checkObjectLiteralAssignment(node: ObjectLiteralExpression, sourceType: Type, contextualMapper?: TypeMapper): Type {
1181111812 const properties = node.properties;
1181211813 for (const p of properties) {
11813- if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) {
11814- const name = <PropertyName>(<PropertyAssignment>p).name;
11815- if (name.kind === SyntaxKind.ComputedPropertyName) {
11816- checkComputedPropertyName(<ComputedPropertyName>name);
11817- }
11818- if (isComputedNonLiteralName(name)) {
11819- continue;
11820- }
11814+ checkObjectLiteralDestructuringPropertyAssignment(sourceType, p, contextualMapper);
11815+ }
11816+ return sourceType;
11817+ }
1182111818
11822- const text = getTextOfPropertyName(name);
11823- const type = isTypeAny(sourceType)
11824- ? sourceType
11825- : getTypeOfPropertyOfType(sourceType, text) ||
11826- isNumericLiteralName(text) && getIndexTypeOfType(sourceType, IndexKind.Number) ||
11827- getIndexTypeOfType(sourceType, IndexKind.String);
11828- if (type) {
11829- if (p.kind === SyntaxKind.ShorthandPropertyAssignment) {
11830- checkDestructuringAssignment(<ShorthandPropertyAssignment>p, type);
11831- }
11832- else {
11833- // non-shorthand property assignments should always have initializers
11834- checkDestructuringAssignment((<PropertyAssignment>p).initializer, type);
11835- }
11819+ function checkObjectLiteralDestructuringPropertyAssignment(objectLiteralType: Type, property: ObjectLiteralElement, contextualMapper?: TypeMapper) {
11820+ if (property.kind === SyntaxKind.PropertyAssignment || property.kind === SyntaxKind.ShorthandPropertyAssignment) {
11821+ const name = <PropertyName>(<PropertyAssignment>property).name;
11822+ if (name.kind === SyntaxKind.ComputedPropertyName) {
11823+ checkComputedPropertyName(<ComputedPropertyName>name);
11824+ }
11825+ if (isComputedNonLiteralName(name)) {
11826+ return undefined;
11827+ }
11828+
11829+ const text = getTextOfPropertyName(name);
11830+ const type = isTypeAny(objectLiteralType)
11831+ ? objectLiteralType
11832+ : getTypeOfPropertyOfType(objectLiteralType, text) ||
11833+ isNumericLiteralName(text) && getIndexTypeOfType(objectLiteralType, IndexKind.Number) ||
11834+ getIndexTypeOfType(objectLiteralType, IndexKind.String);
11835+ if (type) {
11836+ if (property.kind === SyntaxKind.ShorthandPropertyAssignment) {
11837+ return checkDestructuringAssignment(<ShorthandPropertyAssignment>property, type);
1183611838 }
1183711839 else {
11838- error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(sourceType), declarationNameToString(name));
11840+ // non-shorthand property assignments should always have initializers
11841+ return checkDestructuringAssignment((<PropertyAssignment>property).initializer, type);
1183911842 }
1184011843 }
1184111844 else {
11842- error(p , Diagnostics.Property_assignment_expected );
11845+ error(name , Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(objectLiteralType), declarationNameToString(name) );
1184311846 }
1184411847 }
11845- return sourceType;
11848+ else {
11849+ error(property, Diagnostics.Property_assignment_expected);
11850+ }
1184611851 }
1184711852
1184811853 function checkArrayLiteralAssignment(node: ArrayLiteralExpression, sourceType: Type, contextualMapper?: TypeMapper): Type {
@@ -11852,44 +11857,51 @@ namespace ts {
1185211857 const elementType = checkIteratedTypeOrElementType(sourceType, node, /*allowStringInput*/ false) || unknownType;
1185311858 const elements = node.elements;
1185411859 for (let i = 0; i < elements.length; i++) {
11855- const e = elements[i];
11856- if (e.kind !== SyntaxKind.OmittedExpression) {
11857- if (e.kind !== SyntaxKind.SpreadElementExpression) {
11858- const propName = "" + i;
11859- const type = isTypeAny(sourceType)
11860- ? sourceType
11861- : isTupleLikeType(sourceType)
11862- ? getTypeOfPropertyOfType(sourceType, propName)
11863- : elementType;
11864- if (type) {
11865- checkDestructuringAssignment(e, type, contextualMapper);
11860+ checkArrayLiteralDestructuringElementAssignment(node, sourceType, i, elementType, contextualMapper);
11861+ }
11862+ return sourceType;
11863+ }
11864+
11865+ function checkArrayLiteralDestructuringElementAssignment(node: ArrayLiteralExpression, sourceType: Type,
11866+ elementIndex: number, elementType: Type, contextualMapper?: TypeMapper) {
11867+ const elements = node.elements;
11868+ const element = elements[elementIndex];
11869+ if (element.kind !== SyntaxKind.OmittedExpression) {
11870+ if (element.kind !== SyntaxKind.SpreadElementExpression) {
11871+ const propName = "" + elementIndex;
11872+ const type = isTypeAny(sourceType)
11873+ ? sourceType
11874+ : isTupleLikeType(sourceType)
11875+ ? getTypeOfPropertyOfType(sourceType, propName)
11876+ : elementType;
11877+ if (type) {
11878+ return checkDestructuringAssignment(element, type, contextualMapper);
11879+ }
11880+ else {
11881+ if (isTupleType(sourceType)) {
11882+ error(element, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(sourceType), (<TupleType>sourceType).elementTypes.length, elements.length);
1186611883 }
1186711884 else {
11868- if (isTupleType(sourceType)) {
11869- error(e, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(sourceType), (<TupleType>sourceType).elementTypes.length, elements.length);
11870- }
11871- else {
11872- error(e, Diagnostics.Type_0_has_no_property_1, typeToString(sourceType), propName);
11873- }
11885+ error(element, Diagnostics.Type_0_has_no_property_1, typeToString(sourceType), propName);
1187411886 }
1187511887 }
11888+ }
11889+ else {
11890+ if (elementIndex < elements.length - 1) {
11891+ error(element, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern);
11892+ }
1187611893 else {
11877- if (i < elements.length - 1) {
11878- error(e, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern);
11894+ const restExpression = (<SpreadElementExpression>element).expression;
11895+ if (restExpression.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>restExpression).operatorToken.kind === SyntaxKind.EqualsToken) {
11896+ error((<BinaryExpression>restExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer);
1187911897 }
1188011898 else {
11881- const restExpression = (<SpreadElementExpression>e).expression;
11882- if (restExpression.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>restExpression).operatorToken.kind === SyntaxKind.EqualsToken) {
11883- error((<BinaryExpression>restExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer);
11884- }
11885- else {
11886- checkDestructuringAssignment(restExpression, createArrayType(elementType), contextualMapper);
11887- }
11899+ return checkDestructuringAssignment(restExpression, createArrayType(elementType), contextualMapper);
1188811900 }
1188911901 }
1189011902 }
1189111903 }
11892- return sourceType ;
11904+ return undefined ;
1189311905 }
1189411906
1189511907 function checkDestructuringAssignment(exprOrAssignment: Expression | ShorthandPropertyAssignment, sourceType: Type, contextualMapper?: TypeMapper): Type {
@@ -16562,6 +16574,53 @@ namespace ts {
1656216574 return unknownType;
1656316575 }
1656416576
16577+ // Gets the type of object literal or array literal of destructuring assignment.
16578+ // { a } from
16579+ // for ( { a } of elems) {
16580+ // }
16581+ // [ a ] from
16582+ // [a] = [ some array ...]
16583+ function getTypeOfArrayLiteralOrObjectLiteralDestructuringAssignment(expr: Expression): Type {
16584+ Debug.assert(expr.kind === SyntaxKind.ObjectLiteralExpression || expr.kind === SyntaxKind.ArrayLiteralExpression);
16585+ // If this is from "for of"
16586+ // for ( { a } of elems) {
16587+ // }
16588+ if (expr.parent.kind === SyntaxKind.ForOfStatement) {
16589+ const iteratedType = checkRightHandSideOfForOf((<ForOfStatement>expr.parent).expression);
16590+ return checkDestructuringAssignment(expr, iteratedType || unknownType);
16591+ }
16592+ // If this is from "for" initializer
16593+ // for ({a } = elems[0];.....) { }
16594+ if (expr.parent.kind === SyntaxKind.BinaryExpression) {
16595+ const iteratedType = checkExpression((<BinaryExpression>expr.parent).right);
16596+ return checkDestructuringAssignment(expr, iteratedType || unknownType);
16597+ }
16598+ // If this is from nested object binding pattern
16599+ // for ({ skills: { primary, secondary } } = multiRobot, i = 0; i < 1; i++) {
16600+ if (expr.parent.kind === SyntaxKind.PropertyAssignment) {
16601+ const typeOfParentObjectLiteral = getTypeOfArrayLiteralOrObjectLiteralDestructuringAssignment(<Expression>expr.parent.parent);
16602+ return checkObjectLiteralDestructuringPropertyAssignment(typeOfParentObjectLiteral || unknownType, <ObjectLiteralElement>expr.parent);
16603+ }
16604+ // Array literal assignment - array destructuring pattern
16605+ Debug.assert(expr.parent.kind === SyntaxKind.ArrayLiteralExpression);
16606+ // [{ property1: p1, property2 }] = elems;
16607+ const typeOfArrayLiteral = getTypeOfArrayLiteralOrObjectLiteralDestructuringAssignment(<Expression>expr.parent);
16608+ const elementType = checkIteratedTypeOrElementType(typeOfArrayLiteral || unknownType, expr.parent, /*allowStringInput*/ false) || unknownType;
16609+ return checkArrayLiteralDestructuringElementAssignment(<ArrayLiteralExpression>expr.parent, typeOfArrayLiteral,
16610+ indexOf((<ArrayLiteralExpression>expr.parent).elements, expr), elementType || unknownType);
16611+ }
16612+
16613+ // Gets the property symbol corresponding to the property in destructuring assignment
16614+ // 'property1' from
16615+ // for ( { property1: a } of elems) {
16616+ // }
16617+ // 'property1' at location 'a' from:
16618+ // [a] = [ property1, property2 ]
16619+ function getPropertySymbolOfDestructuringAssignment(location: Identifier) {
16620+ // Get the type of the object or array literal and then look for property of given name in the type
16621+ const typeOfObjectLiteral = getTypeOfArrayLiteralOrObjectLiteralDestructuringAssignment(<Expression>location.parent.parent);
16622+ return typeOfObjectLiteral && getPropertyOfType(typeOfObjectLiteral, location.text);
16623+ }
1656516624
1656616625 function getTypeOfExpression(expr: Expression): Type {
1656716626 if (isRightSideOfQualifiedNameOrPropertyAccess(expr)) {
0 commit comments