{"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,"node_id":"MDU6SXNzdWUxNzUzMTEyNDk=","number":10727,"title":"Add spread/rest higher-order types operator","user":{"login":"sandersn","id":293473,"node_id":"MDQ6VXNlcjI5MzQ3Mw==","avatar_url":"https://avatars1.githubusercontent.com/u/293473?v=4","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":[{"id":113971155,"node_id":"MDU6TGFiZWwxMTM5NzExNTU=","url":"https://api.github.com/repos/Microsoft/TypeScript/labels/Suggestion","name":"Suggestion","color":"006b75","default":false}],"state":"open","locked":false,"assignee":{"login":"sandersn","id":293473,"node_id":"MDQ6VXNlcjI5MzQ3Mw==","avatar_url":"https://avatars1.githubusercontent.com/u/293473?v=4","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},"assignees":[{"login":"sandersn","id":293473,"node_id":"MDQ6VXNlcjI5MzQ3Mw==","avatar_url":"https://avatars1.githubusercontent.com/u/293473?v=4","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}],"milestone":{"url":"https://api.github.com/repos/Microsoft/TypeScript/milestones/29","html_url":"https://github.com/Microsoft/TypeScript/milestone/29","labels_url":"https://api.github.com/repos/Microsoft/TypeScript/milestones/29/labels","id":1973940,"node_id":"MDk6TWlsZXN0b25lMTk3Mzk0MA==","number":29,"title":"Future","description":"","creator":{"login":"mhegazy","id":8000722,"node_id":"MDQ6VXNlcjgwMDA3MjI=","avatar_url":"https://avatars3.githubusercontent.com/u/8000722?v=4","gravatar_id":"","url":"https://api.github.com/users/mhegazy","html_url":"https://github.com/mhegazy","followers_url":"https://api.github.com/users/mhegazy/followers","following_url":"https://api.github.com/users/mhegazy/following{/other_user}","gists_url":"https://api.github.com/users/mhegazy/gists{/gist_id}","starred_url":"https://api.github.com/users/mhegazy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mhegazy/subscriptions","organizations_url":"https://api.github.com/users/mhegazy/orgs","repos_url":"https://api.github.com/users/mhegazy/repos","events_url":"https://api.github.com/users/mhegazy/events{/privacy}","received_events_url":"https://api.github.com/users/mhegazy/received_events","type":"User","site_admin":false},"open_issues":397,"closed_issues":0,"state":"open","created_at":"2016-08-31T00:21:08Z","updated_at":"2018-07-06T17:26:04Z","due_on":null,"closed_at":null},"comments":45,"created_at":"2016-09-06T18:00:37Z","updated_at":"2018-07-11T15:42:14Z","closed_at":null,"author_association":"MEMBER","body":"The spread type is a new type operator that types the [TC39 stage 3 object spread operator](https://github.com/sebmarkbage/ecmascript-rest-spread). Its counterpart, the difference type, will type the proposed object rest destructuring operator. The spread type `{ ...A, ...B }` combines the properties, but not the call or construct signatures, of entities A and B.\n\nThe pull request is at #11150. The original issue for spread/rest types is #2103. Note that this proposal deviates from the specification by keeping all properties except methods, not just own enumerable ones.\n## Proposal syntax\n\nThe type syntax in this proposal differs from the type syntax as implemented in order to treat spread as a binary operator. Three rules are needed to convert the `{ ...spread1, ...spread2 }` syntax to binary syntax `spread1 ... spread2`.\n1. `{ ...spread }` becomes `{} ... spread`.\n2. `{ a, b, c, ...d}` becomes `{a, b, c} ... d`\n3. Multiple spreads inside an object literal are treated as sequences of binary spreads: `{ a, b, c, ...d, ...e, f, g}` becomes `{a, b, c} ... d ... e ... { f, g }`.\n## Type Relationships\n- Identity: `A ... A ... A` is equivalent to `A ... A` and `A ... A` is equivalent to `{} ... A`.\n- Commutativity: `A ... B` is _not_ equivalent to `B ... A`. Properties of `B` overwrite properties of `A` with the same name in `A ... B`.\n- Associativity: `(A ... B) ... C` is equivalent to `A ... (B ... C)`. `...` is right-associative.\n- Distributivity: Spread is distributive over `|`, so `A ... (B | C)` is equivalent to `A ... B | A ... C`.\n## Assignment compatibility\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.\n- `X` is assignable to `A ... B` if the properties and index signatures of `X` are assignable to those of `A ... B`.\n### Type parameters\n\nA spread type containing type parameters is assignable to another spread type if the type if the source and target types are both of the form `T ... { some, object, type }` and both source and target have the same type parameter and the source object type is assignable to the target object type.\n### Type inference\n\nSpread types are not type inference targets.\n## Properties and index signatures\n\nIn the following definitions, 'property' means either a property or a get accessor.\n\nThe type `A ... B` has a property `P` if \n1. `A` has a property `P` or `B` has a property `P`, and\n2. Either `A.P` or `B.P` is not a method. \n\nIn this case `(A ... B).P` has the type \n1. Of `B.P` if `B.P` is not optional.\n2. Of `A.P | B.P` if `B.P` is optional and `A` has a property `P`.\n3. Of `A.P` otherwise.\n\n`private`, `protected` and `readonly` behave the same way as optionality except that if `A.P` or `B.P` is `private`, `protected` or `readonly`, then `(A ...B).P` is `private`, `protected` or `readonly`, respectively.\n## Index signatures\n\nThe type `A ... B` has an index signature if `A` has an index signature and `B` has an index signature. The index signature's type is the union of the two index signatures' types.\n## Call and Construct signatures\n\n`A ... B` has no call signatures and no construct signatures, since these are not properties.\n## Precedence\n\nPrecedence of `...` is higher than `&` and `|`. Since the language syntax is that of object type literals, precedence doesn't matter since the braces act as boundaries of the spread type.\n## Examples\n\nTaken from the [TC39 proposal](https://github.com/sebmarkbage/ecmascript-rest-spread/blob/master/Spread.md) and given types.\n### Shallow Clone (excluding prototype)\n\n``` ts\nlet aClone: { ...A } = { ...a };\n```\n### Merging Two Objects\n\n``` ts\nlet ab: { ...A, ...B } = { ...a, ...b };\n```\n### Overriding Properties\n\n``` ts\nlet aWithOverrides: { ...A, x: number, y: number } = { ...a, x: 1, y: 2 };\n// equivalent to\nlet aWithOverrides: { ...A, ...{ x: number, y: number } } = { ...a, ...{ x: 1, y: 2 } };\n```\n### Default Properties\n\n``` ts\nlet aWithDefaults: { x: number, y: number, ...A } = { x: 1, y: 2, ...a };\n```\n### Multiple Merges\n\n``` ts\n// Note: getters on a are executed twice\nlet xyWithAandB: { x: number, ...A, y: number, ...B, ...A } = { x: 1, ...a, y: 2, ...b, ...a };\n// equivalent to\nlet xyWithAandB: { x: number, y: number, ...B, ...A } = { x: 1, ...a, y: 2, ...b, ...a };\n```\n### Getters on the Object Initializer\n\n``` ts\n// Does not throw because .x isn't evaluated yet. It's defined.\nlet aWithXGetter: { ...A, x: never } = { ...a, get x() { throw new Error('not thrown yet') } };\n```\n### Getters in the Spread Object\n\n``` ts\n// Throws because the .x property of the inner object is evaluated when the\n// property value is copied over to the surrounding object initializer.\nlet runtimeError: { ...A, x: never } = { ...a, ...{ get x() { throw new Error('thrown now') } } };\n```\n### Setters Are Not Executed When They're Redefined\n\n``` ts\nlet z: { x: number } = { set x() { throw new Error(); }, ...{ x: 1 } }; // No error\n```\n### Null/Undefined Are Ignored\n\n``` ts\nlet emptyObject: {} = { ...null, ...undefined }; // no runtime error\n```\n### Updating Deep Immutable Object\n\n``` ts\nlet newVersion: { ...A, name: string, address: { address, zipCode: string }, items: { title: string }[] } = {\n  ...previousVersion,\n  name: 'New Name', // Override the name property\n  address: { ...previousVersion.address, zipCode: '99999' } // Update nested zip code\n  items: [...previousVersion.items, { title: 'New Item' }] // Add an item to the list of items\n};\n```\n\nNote: If `A = { name: string, address: { address, zipCode: string }, items: { title: string }[] }`, then the type of newVersion is equivalent to `A`\n# Rest types\n\nThe difference type is the opposite of the spread type. It types the TC39 stage 3 object-rest destructuring operator.  The difference type `rest(T, a, b, c)` represents the type `T` after the properties `a`, `b` and `c` have been removed, as well as call signatures and construct signatures. \n\nA short example illustrates the way this type is used:\n\n``` ts\n/** JavaScript version */\nfunction removeX(o) {\n  let { x, ...rest } = o;\n  return rest;\n}\n\n/** Typescript version */\nfunction removeX<T extends { x: number, y: number }>(o: T): rest(T, x) {\n  let { x, ...rest }: T = o;\n  return rest;\n}\n```\n## Type Relationships\n- `rest(A)` is not equivalent to `A` because it is missing call and construct signatures. \n- `rest(rest(A))` is equivalent to `rest(A)`. \n- `rest(rest(A, a), b)` is equivalent to `rest(rest(A, b), a)` and `rest(A, a, b)`.\n- `rest(A | B, a)` is equivalent to `rest(A, a) | rest(B, a)`.\n## Assignment compatibility\n- `rest(T, x)` is not assignable to `T`.\n- `T` is assignable to `rest(T, x)` because `T` has more properties and signatures.\n## Properties and index signatures\n\nThe type `rest(A, P)` removes `P` from `A` if it exists. Otherwise, it does nothing.\n## Call and Construct signatures\n\n`rest(A)` does not have call or construct signatures.\n## Precedence\n\nDifference types have similar precedence to `-` in the expression grammar, particularly compared to `&` and `|`. TODO: Find out what this precedence is.\n"},"comment":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/comments/404216529","html_url":"https://github.com/Microsoft/TypeScript/issues/10727#issuecomment-404216529","issue_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/10727","id":404216529,"node_id":"MDEyOklzc3VlQ29tbWVudDQwNDIxNjUyOQ==","user":{"login":"mshoho","id":28045781,"node_id":"MDQ6VXNlcjI4MDQ1Nzgx","avatar_url":"https://avatars1.githubusercontent.com/u/28045781?v=4","gravatar_id":"","url":"https://api.github.com/users/mshoho","html_url":"https://github.com/mshoho","followers_url":"https://api.github.com/users/mshoho/followers","following_url":"https://api.github.com/users/mshoho/following{/other_user}","gists_url":"https://api.github.com/users/mshoho/gists{/gist_id}","starred_url":"https://api.github.com/users/mshoho/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mshoho/subscriptions","organizations_url":"https://api.github.com/users/mshoho/orgs","repos_url":"https://api.github.com/users/mshoho/repos","events_url":"https://api.github.com/users/mshoho/events{/privacy}","received_events_url":"https://api.github.com/users/mshoho/received_events","type":"User","site_admin":false},"created_at":"2018-07-11T15:42:14Z","updated_at":"2018-07-11T15:42:14Z","author_association":"MEMBER","body":"@pelotom I have something like this:\r\n\r\n```\r\nfunction someExternalFunction(a: AA) {\r\n    // Something external, out of my control.\r\n}\r\n\r\n// And I need safely typechecked way to:\r\n\r\nsomeExternalFunction(merge(a, b)); // ok.\r\nsomeExternalFunction(merge(a, b)); // compiler error.\r\n```"}}
{"actor":{"display_login":"mshoho"}}