Skip to content

Commit 4c9bdb9

Browse files
authored
Merge pull request #12552 from Microsoft/spreadRestIntersectionAndUnions
Spread & rest over intersection and unions
2 parents aaf0c89 + 505c153 commit 4c9bdb9

40 files changed

+1408
-39
lines changed

src/compiler/checker.ts

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3054,7 +3054,15 @@ namespace ts {
30543054
}
30553055

30563056
function getRestType(source: Type, properties: PropertyName[], symbol: Symbol): Type {
3057-
Debug.assert(!!(source.flags & TypeFlags.Object), "Rest types only support object types right now.");
3057+
source = filterType(source, t => !(t.flags & TypeFlags.Nullable));
3058+
if (source.flags & TypeFlags.Never) {
3059+
return emptyObjectType;
3060+
}
3061+
3062+
if (source.flags & TypeFlags.Union) {
3063+
return mapType(source, t => getRestType(t, properties, symbol));
3064+
}
3065+
30583066
const members = createMap<Symbol>();
30593067
const names = createMap<true>();
30603068
for (const name of properties) {
@@ -3095,7 +3103,7 @@ namespace ts {
30953103
let type: Type;
30963104
if (pattern.kind === SyntaxKind.ObjectBindingPattern) {
30973105
if (declaration.dotDotDotToken) {
3098-
if (!(parentType.flags & TypeFlags.Object)) {
3106+
if (!isValidSpreadType(parentType)) {
30993107
error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types);
31003108
return unknownType;
31013109
}
@@ -6110,11 +6118,25 @@ namespace ts {
61106118
* this function should be called in a left folding style, with left = previous result of getSpreadType
61116119
* and right = the new element to be spread.
61126120
*/
6113-
function getSpreadType(left: Type, right: Type, isFromObjectLiteral: boolean): ResolvedType | IntrinsicType {
6114-
Debug.assert(!!(left.flags & (TypeFlags.Object | TypeFlags.Any)) && !!(right.flags & (TypeFlags.Object | TypeFlags.Any)), "Only object types may be spread.");
6121+
function getSpreadType(left: Type, right: Type, isFromObjectLiteral: boolean): Type {
61156122
if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) {
61166123
return anyType;
61176124
}
6125+
left = filterType(left, t => !(t.flags & TypeFlags.Nullable));
6126+
if (left.flags & TypeFlags.Never) {
6127+
return right;
6128+
}
6129+
right = filterType(right, t => !(t.flags & TypeFlags.Nullable));
6130+
if (right.flags & TypeFlags.Never) {
6131+
return left;
6132+
}
6133+
if (left.flags & TypeFlags.Union) {
6134+
return mapType(left, t => getSpreadType(t, right, isFromObjectLiteral));
6135+
}
6136+
if (right.flags & TypeFlags.Union) {
6137+
return mapType(right, t => getSpreadType(left, t, isFromObjectLiteral));
6138+
}
6139+
61186140
const members = createMap<Symbol>();
61196141
const skippedPrivateMembers = createMap<boolean>();
61206142
let stringIndexInfo: IndexInfo;
@@ -11446,7 +11468,7 @@ namespace ts {
1144611468
typeFlags = 0;
1144711469
}
1144811470
const type = checkExpression((memberDecl as SpreadAssignment).expression);
11449-
if (!(type.flags & (TypeFlags.Object | TypeFlags.Any))) {
11471+
if (!isValidSpreadType(type)) {
1145011472
error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types);
1145111473
return unknownType;
1145211474
}
@@ -11524,6 +11546,12 @@ namespace ts {
1152411546
}
1152511547
}
1152611548

11549+
function isValidSpreadType(type: Type): boolean {
11550+
return !!(type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined) ||
11551+
type.flags & TypeFlags.Object && !isGenericMappedType(type) ||
11552+
type.flags & TypeFlags.UnionOrIntersection && !forEach((<UnionOrIntersectionType>type).types, t => !isValidSpreadType(t)));
11553+
}
11554+
1152711555
function checkJsxSelfClosingElement(node: JsxSelfClosingElement) {
1152811556
checkJsxOpeningLikeElement(node);
1152911557
return jsxElementType || anyType;

src/compiler/transformers/destructuring.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ namespace ts {
459459
var t = {};
460460
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
461461
t[p] = s[p];
462-
if (typeof Object.getOwnPropertySymbols === "function")
462+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
463463
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
464464
t[p[i]] = s[p[i]];
465465
return t;

tests/baselines/reference/objectRest.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ var __rest = (this && this.__rest) || function (s, e) {
4343
var t = {};
4444
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4545
t[p] = s[p];
46-
if (typeof Object.getOwnPropertySymbols === "function")
46+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
4747
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
4848
t[p[i]] = s[p[i]];
4949
return t;

tests/baselines/reference/objectRestAssignment.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ var __rest = (this && this.__rest) || function (s, e) {
1919
var t = {};
2020
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
2121
t[p] = s[p];
22-
if (typeof Object.getOwnPropertySymbols === "function")
22+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
2323
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
2424
t[p[i]] = s[p[i]];
2525
return t;

tests/baselines/reference/objectRestForOf.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ var __rest = (this && this.__rest) || function (s, e) {
2727
var t = {};
2828
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
2929
t[p] = s[p];
30-
if (typeof Object.getOwnPropertySymbols === "function")
30+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
3131
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
3232
t[p[i]] = s[p[i]];
3333
return t;

tests/baselines/reference/objectRestNegative.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ var __rest = (this && this.__rest) || function (s, e) {
2323
var t = {};
2424
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
2525
t[p] = s[p];
26-
if (typeof Object.getOwnPropertySymbols === "function")
26+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
2727
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
2828
t[p[i]] = s[p[i]];
2929
return t;

tests/baselines/reference/objectRestParameter.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ var __rest = (this && this.__rest) || function (s, e) {
2222
var t = {};
2323
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
2424
t[p] = s[p];
25-
if (typeof Object.getOwnPropertySymbols === "function")
25+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
2626
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
2727
t[p[i]] = s[p[i]];
2828
return t;

tests/baselines/reference/objectSpreadNegative.errors.txt

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,18 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,1): error TS2322
77
Property 's' is missing in type '{ b: boolean; }'.
88
tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,36): error TS2300: Duplicate identifier 'b'.
99
tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,53): error TS2300: Duplicate identifier 'b'.
10-
tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,20): error TS2698: Spread types may only be created from object types.
11-
tests/cases/conformance/types/spread/objectSpreadNegative.ts(33,24): error TS2698: Spread types may only be created from object types.
12-
tests/cases/conformance/types/spread/objectSpreadNegative.ts(34,19): error TS2698: Spread types may only be created from object types.
13-
tests/cases/conformance/types/spread/objectSpreadNegative.ts(35,19): error TS2698: Spread types may only be created from object types.
14-
tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,20): error TS2698: Spread types may only be created from object types.
15-
tests/cases/conformance/types/spread/objectSpreadNegative.ts(39,19): error TS2698: Spread types may only be created from object types.
16-
tests/cases/conformance/types/spread/objectSpreadNegative.ts(44,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures.
17-
tests/cases/conformance/types/spread/objectSpreadNegative.ts(48,12): error TS2339: Property 'b' does not exist on type '{}'.
18-
tests/cases/conformance/types/spread/objectSpreadNegative.ts(54,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'.
19-
tests/cases/conformance/types/spread/objectSpreadNegative.ts(58,14): error TS2698: Spread types may only be created from object types.
20-
tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS2698: Spread types may only be created from object types.
10+
tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,19): error TS2698: Spread types may only be created from object types.
11+
tests/cases/conformance/types/spread/objectSpreadNegative.ts(33,19): error TS2698: Spread types may only be created from object types.
12+
tests/cases/conformance/types/spread/objectSpreadNegative.ts(35,20): error TS2698: Spread types may only be created from object types.
13+
tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,19): error TS2698: Spread types may only be created from object types.
14+
tests/cases/conformance/types/spread/objectSpreadNegative.ts(42,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures.
15+
tests/cases/conformance/types/spread/objectSpreadNegative.ts(46,12): error TS2339: Property 'b' does not exist on type '{}'.
16+
tests/cases/conformance/types/spread/objectSpreadNegative.ts(52,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'.
17+
tests/cases/conformance/types/spread/objectSpreadNegative.ts(56,14): error TS2698: Spread types may only be created from object types.
18+
tests/cases/conformance/types/spread/objectSpreadNegative.ts(59,14): error TS2698: Spread types may only be created from object types.
2119

2220

23-
==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (17 errors) ====
21+
==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (15 errors) ====
2422
let o = { a: 1, b: 'no' }
2523

2624
/// private propagates
@@ -66,13 +64,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS269
6664
!!! error TS2300: Duplicate identifier 'b'.
6765
let duplicatedSpread = { ...o, ...o }
6866

69-
// null, undefined and primitives are not allowed
70-
let spreadNull = { ...null };
71-
~~~~~~~
72-
!!! error TS2698: Spread types may only be created from object types.
73-
let spreadUndefind = { ...undefined };
74-
~~~~~~~~~~~~
75-
!!! error TS2698: Spread types may only be created from object types.
67+
// primitives are not allowed
7668
let spreadNum = { ...12 };
7769
~~~~~
7870
!!! error TS2698: Spread types may only be created from object types.

tests/baselines/reference/objectSpreadNegative.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ spread = b; // error, missing 's'
2929
let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' }
3030
let duplicatedSpread = { ...o, ...o }
3131

32-
// null, undefined and primitives are not allowed
33-
let spreadNull = { ...null };
34-
let spreadUndefind = { ...undefined };
32+
// primitives are not allowed
3533
let spreadNum = { ...12 };
3634
let spreadSum = { ...1 + 1 };
3735
spreadSum.toFixed(); // error, no methods from number
@@ -108,9 +106,7 @@ spread = b; // error, missing 's'
108106
// literal repeats are not allowed, but spread repeats are fine
109107
var duplicated = __assign({ b: 'bad' }, o, { b: 'bad' }, o2, { b: 'bad' });
110108
var duplicatedSpread = __assign({}, o, o);
111-
// null, undefined and primitives are not allowed
112-
var spreadNull = __assign({}, null);
113-
var spreadUndefind = __assign({}, undefined);
109+
// primitives are not allowed
114110
var spreadNum = __assign({}, 12);
115111
var spreadSum = __assign({}, 1 + 1);
116112
spreadSum.toFixed(); // error, no methods from number
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//// [restIntersection.ts]
2+
var intersection: { x: number, y: number } & { w: string, z: string };
3+
4+
var rest1: { y: number, w: string, z: string };
5+
var {x, ...rest1 } = intersection;
6+
7+
8+
//// [restIntersection.js]
9+
var __rest = (this && this.__rest) || function (s, e) {
10+
var t = {};
11+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
12+
t[p] = s[p];
13+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
14+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
15+
t[p[i]] = s[p[i]];
16+
return t;
17+
};
18+
var intersection;
19+
var rest1;
20+
var x = intersection.x, rest1 = __rest(intersection, ["x"]);

0 commit comments

Comments
 (0)