Skip to content

Commit 71b28a0

Browse files
authored
Merge pull request microsoft#12310 from Microsoft/check-object-rest-destructuring-assignment
Check object rest destructuring assignment
2 parents b514d7c + 074014e commit 71b28a0

File tree

8 files changed

+51
-12
lines changed

8 files changed

+51
-12
lines changed

src/compiler/checker.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14265,12 +14265,13 @@ namespace ts {
1426514265
function checkObjectLiteralAssignment(node: ObjectLiteralExpression, sourceType: Type): Type {
1426614266
const properties = node.properties;
1426714267
for (const p of properties) {
14268-
checkObjectLiteralDestructuringPropertyAssignment(sourceType, p);
14268+
checkObjectLiteralDestructuringPropertyAssignment(sourceType, p, properties);
1426914269
}
1427014270
return sourceType;
1427114271
}
1427214272

14273-
function checkObjectLiteralDestructuringPropertyAssignment(objectLiteralType: Type, property: ObjectLiteralElementLike) {
14273+
/** Note: If property cannot be a SpreadAssignment, then allProperties does not need to be provided */
14274+
function checkObjectLiteralDestructuringPropertyAssignment(objectLiteralType: Type, property: ObjectLiteralElementLike, allProperties?: ObjectLiteralElementLike[]) {
1427414275
if (property.kind === SyntaxKind.PropertyAssignment || property.kind === SyntaxKind.ShorthandPropertyAssignment) {
1427514276
const name = <PropertyName>(<PropertyAssignment>property).name;
1427614277
if (name.kind === SyntaxKind.ComputedPropertyName) {
@@ -14300,7 +14301,14 @@ namespace ts {
1430014301
}
1430114302
}
1430214303
else if (property.kind === SyntaxKind.SpreadAssignment) {
14303-
checkReferenceExpression(property.expression, Diagnostics.The_target_of_an_object_rest_assignment_must_be_a_variable_or_a_property_access);
14304+
const nonRestNames: PropertyName[] = [];
14305+
if (allProperties) {
14306+
for (let i = 0; i < allProperties.length - 1; i++) {
14307+
nonRestNames.push(allProperties[i].name);
14308+
}
14309+
}
14310+
const type = getRestType(objectLiteralType, nonRestNames, objectLiteralType.symbol);
14311+
return checkDestructuringAssignment(property.expression, type);
1430414312
}
1430514313
else {
1430614314
error(property, Diagnostics.Property_assignment_expected);
@@ -14398,7 +14406,10 @@ namespace ts {
1439814406

1439914407
function checkReferenceAssignment(target: Expression, sourceType: Type, contextualMapper?: TypeMapper): Type {
1440014408
const targetType = checkExpression(target, contextualMapper);
14401-
if (checkReferenceExpression(target, Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access)) {
14409+
const error = target.parent.kind === SyntaxKind.SpreadAssignment ?
14410+
Diagnostics.The_target_of_an_object_rest_assignment_must_be_a_variable_or_a_property_access :
14411+
Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access;
14412+
if (checkReferenceExpression(target, error)) {
1440214413
checkTypeAssignableTo(sourceType, targetType, target, /*headMessage*/ undefined);
1440314414
}
1440414415
return sourceType;

tests/baselines/reference/objectRestNegative.errors.txt

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
11
tests/cases/conformance/types/rest/objectRestNegative.ts(2,10): error TS2462: A rest element must be last in a destructuring pattern
2-
tests/cases/conformance/types/rest/objectRestNegative.ts(3,31): error TS2462: A rest element must be last in a destructuring pattern
3-
tests/cases/conformance/types/rest/objectRestNegative.ts(6,17): error TS2700: Rest types may only be created from object types.
4-
tests/cases/conformance/types/rest/objectRestNegative.ts(11,9): error TS2701: The target of an object rest assignment must be a variable or a property access.
2+
tests/cases/conformance/types/rest/objectRestNegative.ts(6,10): error TS2322: Type '{ a: number; }' is not assignable to type '{ a: string; }'.
3+
Types of property 'a' are incompatible.
4+
Type 'number' is not assignable to type 'string'.
5+
tests/cases/conformance/types/rest/objectRestNegative.ts(9,31): error TS2462: A rest element must be last in a destructuring pattern
6+
tests/cases/conformance/types/rest/objectRestNegative.ts(12,17): error TS2700: Rest types may only be created from object types.
7+
tests/cases/conformance/types/rest/objectRestNegative.ts(17,9): error TS2701: The target of an object rest assignment must be a variable or a property access.
58

69

7-
==== tests/cases/conformance/types/rest/objectRestNegative.ts (4 errors) ====
10+
==== tests/cases/conformance/types/rest/objectRestNegative.ts (5 errors) ====
811
let o = { a: 1, b: 'no' };
912
var { ...mustBeLast, a } = o;
1013
~~~~~~~~~~
1114
!!! error TS2462: A rest element must be last in a destructuring pattern
15+
16+
var b: string;
17+
let notAssignable: { a: string };
18+
({ b, ...notAssignable } = o);
19+
~~~~~~~~~~~~~
20+
!!! error TS2322: Type '{ a: number; }' is not assignable to type '{ a: string; }'.
21+
!!! error TS2322: Types of property 'a' are incompatible.
22+
!!! error TS2322: Type 'number' is not assignable to type 'string'.
23+
24+
1225
function stillMustBeLast({ ...mustBeLast, a }: { a: number, b: string }): void {
1326
~~~~~~~~~~
1427
!!! error TS2462: A rest element must be last in a destructuring pattern

tests/baselines/reference/objectRestNegative.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
//// [objectRestNegative.ts]
22
let o = { a: 1, b: 'no' };
33
var { ...mustBeLast, a } = o;
4+
5+
var b: string;
6+
let notAssignable: { a: string };
7+
({ b, ...notAssignable } = o);
8+
9+
410
function stillMustBeLast({ ...mustBeLast, a }: { a: number, b: string }): void {
511
}
612
function generic<T extends { x, y }>(t: T) {
@@ -24,6 +30,9 @@ var __rest = (this && this.__rest) || function (s, e) {
2430
};
2531
var o = { a: 1, b: 'no' };
2632
var a = o.a;
33+
var b;
34+
var notAssignable;
35+
(b = o.b, o, notAssignable = __rest(o, ["b"]));
2736
function stillMustBeLast(_a) {
2837
var a = _a.a;
2938
}

tests/baselines/reference/objectSpreadNoTransform.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
const y = { a: 'yes', b: 'no' };
33
const o = { x: 1, ...y };
44
var b;
5-
var rest;
5+
var rest: any;
66
({ b, ...rest } = o);
77

88

tests/baselines/reference/objectSpreadNoTransform.symbols

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const o = { x: 1, ...y };
1212
var b;
1313
>b : Symbol(b, Decl(objectSpreadNoTransform.ts, 2, 3))
1414

15-
var rest;
15+
var rest: any;
1616
>rest : Symbol(rest, Decl(objectSpreadNoTransform.ts, 3, 3))
1717

1818
({ b, ...rest } = o);

tests/baselines/reference/objectSpreadNoTransform.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const o = { x: 1, ...y };
1717
var b;
1818
>b : any
1919

20-
var rest;
20+
var rest: any;
2121
>rest : any
2222

2323
({ b, ...rest } = o);

tests/cases/conformance/types/rest/objectRestNegative.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
let o = { a: 1, b: 'no' };
22
var { ...mustBeLast, a } = o;
3+
4+
var b: string;
5+
let notAssignable: { a: string };
6+
({ b, ...notAssignable } = o);
7+
8+
39
function stillMustBeLast({ ...mustBeLast, a }: { a: number, b: string }): void {
410
}
511
function generic<T extends { x, y }>(t: T) {

tests/cases/conformance/types/spread/objectSpreadNoTransform.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
const y = { a: 'yes', b: 'no' };
33
const o = { x: 1, ...y };
44
var b;
5-
var rest;
5+
var rest: any;
66
({ b, ...rest } = o);

0 commit comments

Comments
 (0)