{"action":"created","issue":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/10727","repository_url":"https://api.github.com/repos/Microsoft/TypeScript","labels_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/10727/labels{/name}","comments_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/10727/comments","events_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/10727/events","html_url":"https://github.com/Microsoft/TypeScript/issues/10727","id":175311249,"number":10727,"title":"Add spread/rest types to support proposed object spread/rest ","user":{"login":"sandersn","id":293473,"avatar_url":"https://avatars.githubusercontent.com/u/293473?v=3","gravatar_id":"","url":"https://api.github.com/users/sandersn","html_url":"https://github.com/sandersn","followers_url":"https://api.github.com/users/sandersn/followers","following_url":"https://api.github.com/users/sandersn/following{/other_user}","gists_url":"https://api.github.com/users/sandersn/gists{/gist_id}","starred_url":"https://api.github.com/users/sandersn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sandersn/subscriptions","organizations_url":"https://api.github.com/users/sandersn/orgs","repos_url":"https://api.github.com/users/sandersn/repos","events_url":"https://api.github.com/users/sandersn/events{/privacy}","received_events_url":"https://api.github.com/users/sandersn/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2016-09-06T18:00:37Z","updated_at":"2016-09-06T18:07:18Z","closed_at":null,"body":"The spread type is a new type operator that types the proposed (TS39 stage 2) object spread operator. Its counterpart, the subtraction type, will type the proposed object rest destructuring operator. The spread type `{ ...A, ...B }` combines the own, enumerable properties of entities A and B.\r\n\r\nUnlike most type operators, spread is n-ary, not unary like `typeof` or binary like `&`. It takes one or many arguments.\r\n\r\nObject rest and spread is experimental and will be available behind the flag `--experimentalObjectSpreadRest`. Work is happening at [the branch object-rest-spread-WIP](https://github.com/Microsoft/TypeScript/compare/master...object-rest-spread-WIP). The original issue for spread/rest types is #2103.\r\n\r\nThe meat of the definition is in the [Properties and Index Signatures](#properties-and-index-signatures) section. In the interests of brevity I only show the two-spread definition and the one-spread definition if it is interestingly different. Definitions for larger numbers of spreads can be derived easily.\r\n\r\n## Non-spread elements\r\n\r\nNon-spread elements can be treated as spread elements by grouping adjacent non-spread elements into a object literal and then spreading it. Like so:\r\n\r\n```ts\r\n{ ...a, b, c, ...d, e }\r\n=>\r\n{ ...a, ...{ b, c }, ...d, ...{ e } }\r\n```\r\n\r\n## Type Relationships\r\n\r\n * Identity: `{ ...A }` is equivalent to the *enumerable* and *own* properties of `A`. `{ ...A}` is equivalent to `{ ...A, ...A }` and `{ ...A, ...A, ...A }` and so on. \r\n * Commutativity: `{ ...A, ...B }` is *not* equivalent to `{ ...B, ...A}`. Properties of `B` overwrite properties of `A` with the same name.\r\n * Associativity: `{ ...{ ...A, ...B }, ...C}` is equivalent to `{ ...A, { ...B, ...C } }`.\r\n * Supertype reconstruction: `{ ...A, ...B }` is equivalent to the enumerable properties of `A` if `B` is a supertype of `A`.\r\n\r\nNote that methods are not enumerable, so the most noticeable effect of spreading a class instance is that the resulting object is missing all the original's methods.\r\n\r\n## Assignment compatibility\r\n\r\n * `{ ...A, ...B }` is assignable to `X` if the properties and index signatures of `{ ...A, ...B }` are assignable to those of `X`, and `X` has no call or construct signatures.\r\n * `X` is assignable to `{ ...A, ...B }` if the properties and index signatures of `X` are assignable to those of `{ ...A, ...B }`.\r\n\r\n## Properties and index signatures\r\n\r\nThe type `{ ...A }` has a property `P` if `A` has an own, enumerable property `P`. `{ ...A }.P` has the same type as `A.P`.\r\n\r\nThe type `{ ...A, ...B }` has a property `P` if `A` has an own, enumerable property `P` or `B` has an own, enumerable property `P`. In this case `{ ...A, ...B }.P` has the type \r\n 1. of `A.P` if `B` does not have an own, enumerable property `P`.\r\n 2. Of `B.P` if `A` does not have an own enumerable property `P`.\r\n 3. Of `B.P` if `B` has an own enumerable property `P` that is not optional.\r\n 4. Of `A.P | B.P` if `B.P` is optional (and own enumerable). \r\n\r\nFor larger numbers of spreads, we can extend rules (1) &ndash; (4) of the binary case:\r\n\r\nThe type `{ ...A, ...B, ...C }` has a property `P` if any of the spreads have a property `P`. The type of this property is the type of the first non-optional `P` in some spread *S*, looking from the end of the spread list, unioned with all optional properties `P` in spreads that follow *S*.\r\n\r\nIndex signatures spread the same way as properties. \r\n\r\n## Call and Constructor signatures\r\n\r\n`{ ...A, ...B }` has no call signatures and no construct signatures, since these are not own enumerable properties.\r\n\r\n## Precedence\r\n\r\nPrecedence doesn't matter since the spread syntax has required boundaries -- braces -- that aren't ambiguous with anything else.\r\n\r\n## Problems\r\n 1. Exceptions interrupt the copying task. This means things of type `never` might change the type to never.\r\n\r\n## Examples\r\nTaken from the [TC39 proposal](https://github.com/sebmarkbage/ecmascript-rest-spread/blob/master/Spread.md) and given types.\r\n\r\n### Shallow Clone (excluding prototype)\r\n\r\n```ts\r\nlet aClone: { ...A } = { ...a };\r\n```\r\n\r\n### Merging Two Objects\r\n\r\n```ts\r\nlet ab: { ...A, ...B } = { ...a, ...b };\r\n```\r\n\r\n### Overriding Properties\r\n\r\n```ts\r\nlet aWithOverrides: { ...A, x: number, y: number } = { ...a, x: 1, y: 2 };\r\n// equivalent to\r\nlet aWithOverrides: { ...A, ...{ x: number, y: number } } = { ...a, ...{ x: 1, y: 2 } };\r\n```\r\n\r\n### Default Properties\r\n\r\n```ts\r\nlet aWithDefaults: { x: number, y: number, ...A } = { x: 1, y: 2, ...a };\r\n```\r\n\r\n### Multiple Merges\r\n\r\n```ts\r\n// Note: getters on a are executed twice\r\nlet xyWithAandB: { x: number, ...A, y: number, ...B, ...A } = { x: 1, ...a, y: 2, ...b, ...a };\r\n// equivalent to\r\nlet xyWithAandB: { x: number, y: number, ...B, ...A } = { x: 1, ...a, y: 2, ...b, ...a };\r\n```\r\n\r\n### Getters on the Object Initializer\r\n\r\n```ts\r\n// Does not throw because .x isn't evaluated yet. It's defined.\r\nlet aWithXGetter: { ...A, x: never } = { ...a, get x() { throw new Error('not thrown yet') } };\r\n```\r\n\r\n### Getters in the Spread Object\r\n\r\n```ts\r\n// Throws because the .x property of the inner object is evaluated when the\r\n// property value is copied over to the surrounding object initializer.\r\nlet runtimeError: { ...A, x: never } = { ...a, ...{ get x() { throw new Error('thrown now') } } };\r\n```\r\n\r\n### Setters Are Not Executed When They're Redefined\r\n\r\n```ts\r\nlet z: { x: number } = { set x() { throw new Error(); }, ...{ x: 1 } }; // No error\r\n```\r\n\r\n### Null/Undefined Are Ignored\r\n\r\n```ts\r\nlet emptyObject: {} = { ...null, ...undefined }; // no runtime error\r\n```\r\n\r\n### Updating Deep Immutable Object\r\n\r\n```ts\r\nlet newVersion: { ...A, name: string, address: { address, zipCode: string }, items: { title: string }[] } = {\r\n  ...previousVersion,\r\n  name: 'New Name', // Override the name property\r\n  address: { ...previousVersion.address, zipCode: '99999' } // Update nested zip code\r\n  items: [...previousVersion.items, { title: 'New Item' }] // Add an item to the list of items\r\n};\r\n```\r\n\r\nNote: If `A = { name: string, address: { address, zipCode: string }, items: { title: string }[] }`, then the type of newVersion is equivalent to `A`\r\n\r\n# Subtraction types\r\n\r\nThe subtraction type is the opposite of the spread type. It types the proposed (TC39 stage 2) object-rest destructuring operator, along with similar type-shrinking operations.  The subtraction type `A - B` represents all of the enumerable, own properties of A that do not occur in B. \r\n\r\nUnlike the spread type, but like most other type operators, the subtraction type is binary. That's because the rest syntax only supports subtraction from a single object at a time. \r\n\r\nA short example illustrates the way this type is used:\r\n\r\n```ts\r\n/** JavaScript version */\r\nfunction removeX(o) {\r\n  let { x, ...rest } = o;\r\n  return rest;\r\n}\r\n\r\n/** Typescript version */\r\nfunction removeX<T extends { x: number, y: number }>(o: T) {\r\n  let { x, ...rest }: T - { x: number } = o;\r\n  return rest;\r\n}\r\n```\r\n\r\n\r\n## Problems\r\n\r\nThe subtraction type proposal is not finished. It outlines subtraction types but they are not really a good fit for object rest destructuring.\r\n\r\n 1. Subtraction types are not limited to own, enumerable properties. There are plenty of use cases besides object rest destructuring that do not need this limitation.\r\n 2. Subtraction types are more generic than object rest destructuring needs in any case. For object rest, the right-hand-side of the subtraction type will always be a concrete type, never a type variable. That's because you have to subtract specific properties in the object rest destructuring syntax: in `{ x, y, z, ...rest}`, only `rest` can have a generic type. `{ x, y, z }` must be enumerated.\r\nOn the other hand, a separate rest type would still be very similar to a subtraction type. The difference is not observable in many uses. This is just like the difference between intersection types and spread types, but it feels wrong to introduce the more specific type earlier since people will try to use it more generally.\r\n\r\nPerhaps the right answer is to introduce both types at once. Or introduce just subtraction types and find a way to adapt them to object rest destructuring.\r\n\r\n## Type Relationships\r\n\r\n * Identity: `A - {}` is equivalent to the own, enumerable properties of `A`. However, `A - A` is always equivalent to `{}`.\r\n * Commutativity: `A - B` is *not* equivalent to `B - A`. The first removes own, enumerable properties of `A` and the second removes own, enumerable properties of `B`.\r\n * Associativity: `(A - B) - C` is *not* equivalent to `A - (B - C)`. (Consider the example where A, B, and C are all `{ x }`.)\r\n\r\n## Assignment compatibility\r\n\r\n * `A - B` is assignable to `X` if the properties and index signatures of `A - B` are assignable to those of `X`, and `X` has no call or construct signatures.*\r\n * `X` is assignable to `A - B` if the properties and index signatures of `X` are assignable to those of `A - B`.\r\n\r\n## Properties and index signatures\r\n\r\nThe type `A - B` has a property `P` if `A` has an own, enumerable property `P` and `B` does not have an own, enumerable property `P`. In this case `A - B.P` has the type of `A.P`.\r\n\r\n## Call and Constructor signatures\r\n\r\n`A - B` has no call signatures and no construct signatures. Since these are not own enumerable properties.\r\n\r\n## Precedence\r\n\r\nSubtraction types have similar precedence to `-` in the expression grammar, particularly compared to `&` and `|`. TODO: Find out what this precedence is.\r\n"},"comment":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/comments/245037711","html_url":"https://github.com/Microsoft/TypeScript/issues/10727#issuecomment-245037711","issue_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/10727","id":245037711,"user":{"login":"sandersn","id":293473,"avatar_url":"https://avatars.githubusercontent.com/u/293473?v=3","gravatar_id":"","url":"https://api.github.com/users/sandersn","html_url":"https://github.com/sandersn","followers_url":"https://api.github.com/users/sandersn/followers","following_url":"https://api.github.com/users/sandersn/following{/other_user}","gists_url":"https://api.github.com/users/sandersn/gists{/gist_id}","starred_url":"https://api.github.com/users/sandersn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sandersn/subscriptions","organizations_url":"https://api.github.com/users/sandersn/orgs","repos_url":"https://api.github.com/users/sandersn/repos","events_url":"https://api.github.com/users/sandersn/events{/privacy}","received_events_url":"https://api.github.com/users/sandersn/received_events","type":"User","site_admin":false},"created_at":"2016-09-06T18:07:17Z","updated_at":"2016-09-06T18:07:17Z","body":"@ahejlsberg @RyanCavanaugh can you take a look at the spread type section and see if there's something I forgot to take into account? The rest type section isn't really done because I want to talk about the problems in person."}}
{"actor":{"display_login":"sandersn"}}