From b4c15982ff1caceedc496e6fbdee276a793de554 Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Wed, 18 Jan 2017 14:57:20 +0800 Subject: [PATCH 1/2] fix #13556: enable rest/spread on `object` --- src/compiler/checker.ts | 4 ++-- .../nonPrimitiveAccessProperty.errors.txt | 8 +++++++- .../reference/nonPrimitiveAccessProperty.js | 14 ++++++++++++++ tests/baselines/reference/objectSpread.js | 4 ++++ tests/baselines/reference/objectSpread.symbols | 4 ++++ tests/baselines/reference/objectSpread.types | 7 +++++++ .../reference/objectSpreadNegative.errors.txt | 14 +++++++++++--- tests/baselines/reference/objectSpreadNegative.js | 9 +++++++++ .../nonPrimitive/nonPrimitiveAccessProperty.ts | 3 +++ .../cases/conformance/types/spread/objectSpread.ts | 2 ++ .../types/spread/objectSpreadNegative.ts | 5 +++++ 11 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 963d2e77c1b..97ca01bc086 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1,4 +1,4 @@ -/// +/// /// /* @internal */ @@ -11784,7 +11784,7 @@ namespace ts { } function isValidSpreadType(type: Type): boolean { - return !!(type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined) || + return !!(type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined | TypeFlags.NonPrimitive) || type.flags & TypeFlags.Object && !isGenericMappedType(type) || type.flags & TypeFlags.UnionOrIntersection && !forEach((type).types, t => !isValidSpreadType(t))); } diff --git a/tests/baselines/reference/nonPrimitiveAccessProperty.errors.txt b/tests/baselines/reference/nonPrimitiveAccessProperty.errors.txt index 8ef94c64448..0a6dfa66b86 100644 --- a/tests/baselines/reference/nonPrimitiveAccessProperty.errors.txt +++ b/tests/baselines/reference/nonPrimitiveAccessProperty.errors.txt @@ -1,10 +1,16 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts(3,3): error TS2339: Property 'nonExist' does not exist on type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts(5,7): error TS2459: Type 'object' has no property 'destructuring' and no string index signature. -==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts (1 errors) ==== +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts (2 errors) ==== var a: object; a.toString(); a.nonExist(); // error ~~~~~~~~ !!! error TS2339: Property 'nonExist' does not exist on type 'object'. + + var { destructuring } = a; // error + ~~~~~~~~~~~~~ +!!! error TS2459: Type 'object' has no property 'destructuring' and no string index signature. + var { ...rest } = a; // ok \ No newline at end of file diff --git a/tests/baselines/reference/nonPrimitiveAccessProperty.js b/tests/baselines/reference/nonPrimitiveAccessProperty.js index a71b2aba865..abfe2605e32 100644 --- a/tests/baselines/reference/nonPrimitiveAccessProperty.js +++ b/tests/baselines/reference/nonPrimitiveAccessProperty.js @@ -2,9 +2,23 @@ var a: object; a.toString(); a.nonExist(); // error + +var { destructuring } = a; // error +var { ...rest } = a; // ok //// [nonPrimitiveAccessProperty.js] +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; var a; a.toString(); a.nonExist(); // error +var destructuring = a.destructuring; // error +var rest = __rest(a, []); // ok diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js index 4305e17ab31..259b86628a5 100644 --- a/tests/baselines/reference/objectSpread.js +++ b/tests/baselines/reference/objectSpread.js @@ -78,6 +78,8 @@ let computedAfter: { a: number, b: string, "at the end": number } = // shortcut syntax let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } +// non primitive +let spreadNonPrimitve = { ...{}} @@ -148,4 +150,6 @@ var computedAfter = __assign({}, o, (_c = { b: 'yeah' }, _c['at the end'] = 14, // shortcut syntax var a = 12; var shortCutted = __assign({}, o, { a: a }); +// non primitive +var spreadNonPrimitve = __assign({}, {}); var _a, _b, _c; diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index 35c10faa9c0..69c9ed34341 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -316,4 +316,8 @@ let shortCutted: { a: number, b: string } = { ...o, a } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) >a : Symbol(a, Decl(objectSpread.ts, 78, 51)) +// non primitive +let spreadNonPrimitve = { ...{}} +>spreadNonPrimitve : Symbol(spreadNonPrimitve, Decl(objectSpread.ts, 80, 3)) + diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index a571bd0bb63..8a8df1a497f 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -407,4 +407,11 @@ let shortCutted: { a: number, b: string } = { ...o, a } >o : { a: number; b: string; } >a : number +// non primitive +let spreadNonPrimitve = { ...{}} +>spreadNonPrimitve : { constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string): boolean; } +>{ ...{}} : { constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string): boolean; } +>{} : object +>{} : {} + diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 17f07bc06a2..2b0960996ff 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -14,11 +14,12 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,19): error TS269 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. tests/cases/conformance/types/spread/objectSpreadNegative.ts(46,12): error TS2339: Property 'b' does not exist on type '{}'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(52,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(56,14): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(59,14): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(57,11): error TS2339: Property 'a' does not exist on type '{ constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string): boolean; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,14): error TS2698: Spread types may only be created from object types. -==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (15 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (16 errors) ==== let o = { a: 1, b: 'no' } /// private propagates @@ -101,6 +102,13 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(59,14): error TS269 ~ !!! error TS2339: Property 'm' does not exist on type '{ p: number; }'. + // non primitive + let obj: object = { a: 123 }; + let spreadObj = { ...obj }; + spreadObj.a; // error 'a' is not in {} + ~ +!!! error TS2339: Property 'a' does not exist on type '{ constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string): boolean; }'. + // generics function f(t: T, u: U) { return { ...t, ...u, id: 'id' }; diff --git a/tests/baselines/reference/objectSpreadNegative.js b/tests/baselines/reference/objectSpreadNegative.js index dff84355370..fd834b6ef9c 100644 --- a/tests/baselines/reference/objectSpreadNegative.js +++ b/tests/baselines/reference/objectSpreadNegative.js @@ -52,6 +52,11 @@ let c: C = new C() let spreadC = { ...c } spreadC.m(); // error 'm' is not in '{ ... c }' +// non primitive +let obj: object = { a: 123 }; +let spreadObj = { ...obj }; +spreadObj.a; // error 'a' is not in {} + // generics function f(t: T, u: U) { return { ...t, ...u, id: 'id' }; @@ -132,6 +137,10 @@ var C = (function () { var c = new C(); var spreadC = __assign({}, c); spreadC.m(); // error 'm' is not in '{ ... c }' +// non primitive +var obj = { a: 123 }; +var spreadObj = __assign({}, obj); +spreadObj.a; // error 'a' is not in {} // generics function f(t, u) { return __assign({}, t, u, { id: 'id' }); diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts index 2febbb1e2ca..cf902c12e65 100644 --- a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts @@ -1,3 +1,6 @@ var a: object; a.toString(); a.nonExist(); // error + +var { destructuring } = a; // error +var { ...rest } = a; // ok diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts index ebf2bdb2ade..c4562e6f196 100644 --- a/tests/cases/conformance/types/spread/objectSpread.ts +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -78,4 +78,6 @@ let computedAfter: { a: number, b: string, "at the end": number } = // shortcut syntax let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } +// non primitive +let spreadNonPrimitve = { ...{}} diff --git a/tests/cases/conformance/types/spread/objectSpreadNegative.ts b/tests/cases/conformance/types/spread/objectSpreadNegative.ts index 6d1e0dde429..c3b42b31aa9 100644 --- a/tests/cases/conformance/types/spread/objectSpreadNegative.ts +++ b/tests/cases/conformance/types/spread/objectSpreadNegative.ts @@ -52,6 +52,11 @@ let c: C = new C() let spreadC = { ...c } spreadC.m(); // error 'm' is not in '{ ... c }' +// non primitive +let obj: object = { a: 123 }; +let spreadObj = { ...obj }; +spreadObj.a; // error 'a' is not in {} + // generics function f(t: T, u: U) { return { ...t, ...u, id: 'id' }; From 24bb21c55a1842393d523d8b4a26f5f230d24e10 Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Tue, 24 Jan 2017 11:24:30 +0800 Subject: [PATCH 2/2] address code review --- src/compiler/checker.ts | 11 +++++++---- tests/baselines/reference/objectSpread.js | 5 ++--- tests/baselines/reference/objectSpread.symbols | 5 ++--- tests/baselines/reference/objectSpread.types | 7 +++---- .../reference/objectSpreadNegative.errors.txt | 4 ++-- tests/cases/conformance/types/spread/objectSpread.ts | 3 +-- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 97ca01bc086..1a1cea4633f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6291,6 +6291,9 @@ namespace ts { if (right.flags & TypeFlags.Union) { return mapType(right, t => getSpreadType(left, t)); } + if (right.flags & TypeFlags.NonPrimitive) { + return emptyObjectType; + } const members = createMap(); const skippedPrivateMembers = createMap(); @@ -15719,12 +15722,12 @@ namespace ts { } } - /** + /** * Static members being set on a constructor function may conflict with built-in properties - * of Function. Esp. in ECMAScript 5 there are non-configurable and non-writable - * built-in properties. This check issues a transpile error when a class has a static + * of Function. Esp. in ECMAScript 5 there are non-configurable and non-writable + * built-in properties. This check issues a transpile error when a class has a static * member with the same name as a non-writable built-in property. - * + * * @see http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.3 * @see http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.5 * @see http://www.ecma-international.org/ecma-262/6.0/#sec-properties-of-the-function-constructor diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js index 259b86628a5..2bc3b9e11bd 100644 --- a/tests/baselines/reference/objectSpread.js +++ b/tests/baselines/reference/objectSpread.js @@ -79,8 +79,7 @@ let computedAfter: { a: number, b: string, "at the end": number } = let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } // non primitive -let spreadNonPrimitve = { ...{}} - +let spreadNonPrimitive = { ...{}}; //// [objectSpread.js] @@ -151,5 +150,5 @@ var computedAfter = __assign({}, o, (_c = { b: 'yeah' }, _c['at the end'] = 14, var a = 12; var shortCutted = __assign({}, o, { a: a }); // non primitive -var spreadNonPrimitve = __assign({}, {}); +var spreadNonPrimitive = __assign({}, {}); var _a, _b, _c; diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index 69c9ed34341..1ec2520e166 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -317,7 +317,6 @@ let shortCutted: { a: number, b: string } = { ...o, a } >a : Symbol(a, Decl(objectSpread.ts, 78, 51)) // non primitive -let spreadNonPrimitve = { ...{}} ->spreadNonPrimitve : Symbol(spreadNonPrimitve, Decl(objectSpread.ts, 80, 3)) - +let spreadNonPrimitive = { ...{}}; +>spreadNonPrimitive : Symbol(spreadNonPrimitive, Decl(objectSpread.ts, 80, 3)) diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index 8a8df1a497f..950dab43465 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -408,10 +408,9 @@ let shortCutted: { a: number, b: string } = { ...o, a } >a : number // non primitive -let spreadNonPrimitve = { ...{}} ->spreadNonPrimitve : { constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string): boolean; } ->{ ...{}} : { constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string): boolean; } +let spreadNonPrimitive = { ...{}}; +>spreadNonPrimitive : {} +>{ ...{}} : {} >{} : object >{} : {} - diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 2b0960996ff..d9106d651a3 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -14,7 +14,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,19): error TS269 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. tests/cases/conformance/types/spread/objectSpreadNegative.ts(46,12): error TS2339: Property 'b' does not exist on type '{}'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(52,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(57,11): error TS2339: Property 'a' does not exist on type '{ constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string): boolean; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(57,11): error TS2339: Property 'a' does not exist on type '{}'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,14): error TS2698: Spread types may only be created from object types. @@ -107,7 +107,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,14): error TS269 let spreadObj = { ...obj }; spreadObj.a; // error 'a' is not in {} ~ -!!! error TS2339: Property 'a' does not exist on type '{ constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string): boolean; }'. +!!! error TS2339: Property 'a' does not exist on type '{}'. // generics function f(t: T, u: U) { diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts index c4562e6f196..59b93bdd9e4 100644 --- a/tests/cases/conformance/types/spread/objectSpread.ts +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -79,5 +79,4 @@ let computedAfter: { a: number, b: string, "at the end": number } = let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } // non primitive -let spreadNonPrimitve = { ...{}} - +let spreadNonPrimitive = { ...{}};