@@ -83,6 +83,7 @@ namespace ts {
83
83
getShorthandAssignmentValueSymbol,
84
84
getExportSpecifierLocalTargetSymbol,
85
85
getTypeAtLocation: getTypeOfNode,
86
+ getPropertySymbolOfDestructuringAssignment,
86
87
typeToString,
87
88
getSymbolDisplayBuilder,
88
89
symbolToString,
@@ -11810,39 +11811,43 @@ namespace ts {
11810
11811
function checkObjectLiteralAssignment(node: ObjectLiteralExpression, sourceType: Type, contextualMapper?: TypeMapper): Type {
11811
11812
const properties = node.properties;
11812
11813
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
+ }
11821
11818
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);
11836
11838
}
11837
11839
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);
11839
11842
}
11840
11843
}
11841
11844
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) );
11843
11846
}
11844
11847
}
11845
- return sourceType;
11848
+ else {
11849
+ error(property, Diagnostics.Property_assignment_expected);
11850
+ }
11846
11851
}
11847
11852
11848
11853
function checkArrayLiteralAssignment(node: ArrayLiteralExpression, sourceType: Type, contextualMapper?: TypeMapper): Type {
@@ -11852,44 +11857,51 @@ namespace ts {
11852
11857
const elementType = checkIteratedTypeOrElementType(sourceType, node, /*allowStringInput*/ false) || unknownType;
11853
11858
const elements = node.elements;
11854
11859
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);
11866
11883
}
11867
11884
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);
11874
11886
}
11875
11887
}
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
+ }
11876
11893
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);
11879
11897
}
11880
11898
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);
11888
11900
}
11889
11901
}
11890
11902
}
11891
11903
}
11892
- return sourceType ;
11904
+ return undefined ;
11893
11905
}
11894
11906
11895
11907
function checkDestructuringAssignment(exprOrAssignment: Expression | ShorthandPropertyAssignment, sourceType: Type, contextualMapper?: TypeMapper): Type {
@@ -16562,6 +16574,53 @@ namespace ts {
16562
16574
return unknownType;
16563
16575
}
16564
16576
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
+ }
16565
16624
16566
16625
function getTypeOfExpression(expr: Expression): Type {
16567
16626
if (isRightSideOfQualifiedNameOrPropertyAccess(expr)) {
0 commit comments