{"action":"created","issue":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/24897","repository_url":"https://api.github.com/repos/Microsoft/TypeScript","labels_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/24897/labels{/name}","comments_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/24897/comments","events_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/24897/events","html_url":"https://github.com/Microsoft/TypeScript/pull/24897","id":331436630,"node_id":"MDExOlB1bGxSZXF1ZXN0MTk0MTY1NTEx","number":24897,"title":"Tuples in rest parameters and spread expressions","user":{"login":"ahejlsberg","id":4226954,"node_id":"MDQ6VXNlcjQyMjY5NTQ=","avatar_url":"https://avatars1.githubusercontent.com/u/4226954?v=4","gravatar_id":"","url":"https://api.github.com/users/ahejlsberg","html_url":"https://github.com/ahejlsberg","followers_url":"https://api.github.com/users/ahejlsberg/followers","following_url":"https://api.github.com/users/ahejlsberg/following{/other_user}","gists_url":"https://api.github.com/users/ahejlsberg/gists{/gist_id}","starred_url":"https://api.github.com/users/ahejlsberg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ahejlsberg/subscriptions","organizations_url":"https://api.github.com/users/ahejlsberg/orgs","repos_url":"https://api.github.com/users/ahejlsberg/repos","events_url":"https://api.github.com/users/ahejlsberg/events{/privacy}","received_events_url":"https://api.github.com/users/ahejlsberg/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":30,"created_at":"2018-06-12T04:52:31Z","updated_at":"2018-06-15T02:31:04Z","closed_at":null,"author_association":"MEMBER","pull_request":{"url":"https://api.github.com/repos/Microsoft/TypeScript/pulls/24897","html_url":"https://github.com/Microsoft/TypeScript/pull/24897","diff_url":"https://github.com/Microsoft/TypeScript/pull/24897.diff","patch_url":"https://github.com/Microsoft/TypeScript/pull/24897.patch"},"body":"This PR includes the following:\r\n\r\n* Expansion of rest parameters with tuple types into discrete parameters.\r\n* Expansion of spread expressions with tuple types into discrete arguments.\r\n* Generic rest parameters and corresponding inference of tuple types.\r\n* Optional elements in tuple types.\r\n* Open-ended tuple types (in progress).\r\n\r\nWith these features it becomes possible to strongly type a number of higher-order functions that transform functions and their parameter lists (such as JavaScript's `bind`, `call`, and `apply`).\r\n\r\nThe PR implements the a number of the capabilities discussed in #5453, but with considerably less complexity.\r\n\r\n## Rest parameters with tuple types\r\n\r\nWhen a rest parameter has a tuple type, the tuple type is expanded into a sequence of discrete parameters. For example the following two declarations are equivalent:\r\n\r\n```ts\r\ndeclare function foo(...args: [number, string, boolean]): void;\r\ndeclare function foo(args_0: number, args_1: string, args_2: boolean): void;\r\n```\r\n\r\n## Spread expressions with tuple types\r\n\r\nWhen a function call includes a spread expression of a tuple type as the last argument, the spread expression corresponds to a sequence of discrete arguments of the tuple element types. Thus, the following calls are equivalent:\r\n\r\n```ts\r\nconst args: [number, string, boolean] = [42, \"hello\", true];\r\nfoo(42, \"hello\", true);\r\nfoo(args[0], args[1], args[2]);\r\nfoo(...args);\r\n```\r\n\r\n## Generic rest parameters\r\n\r\nA rest parameter is permitted to have a generic type that is constrained to an array type, and type inference can infer tuple types for such generic rest parameters. This enables higher-order capturing and spreading of partial parameter lists:\r\n\r\n```ts\r\ndeclare function bind<T, U extends any[], V>(f: (x: T, ...args: U) => V, x: T): (...args: U) => V;\r\n\r\ndeclare function f3(x: number, y: string, z: boolean): void;\r\n\r\nconst f2 = bind(f3, 42);  // (y: string, z: boolean) => void\r\nconst f1 = bind(f2, \"hello\");  // (z: boolean) => void\r\nconst f0 = bind(f1, true);  // () => void\r\n\r\nf3(42, \"hello\", true);\r\nf2(\"hello\", true);\r\nf1(true);\r\nf0();\r\n```\r\n\r\nIn the declaration of `f2` above, type inference infers types `number`, `[string, boolean]` and `void` for `T`, `U` and `V` respectively.\r\n\r\nNote that when a tuple type is inferred from a sequence of parameters and later expanded into a parameter list, as is the case for `U`, the original parameter names are used in the expansion (however, the names have no semantic meaning and are not otherwise observable).\r\n\r\n## Optional elements in tuple types\r\n\r\nTuple types now permit a `?` postfix on element types to indicate that the element is optional:\r\n\r\n```ts\r\nlet t: [number, string?, boolean?];\r\nt = [42, \"hello\", true];\r\nt = [42, \"hello\"];\r\nt = [42];\r\n```\r\n\r\nIn `--strictNullChecks` mode, a `?` modifier automatically includes `undefined` in the element type, similar to optional parameters.\r\n\r\nA tuple type permits an element to be omitted if it has a postfix `?` modifier on its type and all elements to the right of it also have `?` modifiers.\r\n\r\nWhen tuple types are inferred for rest parameters, optional parameters in the source become optional tuple elements in the inferred type.\r\n\r\nThe `length` property of a tuple type with optional elements is a union of numeric literal types representing the possible lengths. For example, the type of the `length` property in the tuple type `[number, string?, boolean?]` is `1 | 2 | 3`.\r\n\r\n## Open-ended tuple types\r\n\r\n_Upcoming commits will implement the following_:\r\n\r\n_EDIT: Updated to reflect change from `string*` to `...string[]` syntax for rest elements._\r\n\r\nThe last element of a tuple type can be a rest element of the form `...X`, where `X` is an array type. A rest element indicates that the tuple type is open-ended and may have zero or more additional elements of the array element type. For example, `[number, ...string[]]` means tuples with a `number` element followed by any number of `string` elements.\r\n\r\n```ts\r\nfunction tuple<T extends any[]>(...args: T): T {\r\n    return args;\r\n}\r\n\r\nconst numbers: number[] = getArrayOfNumbers();\r\nconst t1 = tuple(\"foo\", 1, true);  // [string, number, boolean]\r\nconst t2 = tuple(\"bar\", ...numbers);  // [string, ...number[]]\r\n```\r\n\r\n## Strong typing of bind, call, and apply\r\n\r\nWith this PR it becomes possible to strongly type the `bind`, `call`, and `apply` methods on function objects. This is however a breaking change for some existing code so we need to investigate the repercussions.\r\n\r\nFixes #1024.\r\nFixes #4130.\r\nFixes #5331.\r\n"},"comment":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/comments/397495318","html_url":"https://github.com/Microsoft/TypeScript/pull/24897#issuecomment-397495318","issue_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/24897","id":397495318,"node_id":"MDEyOklzc3VlQ29tbWVudDM5NzQ5NTMxOA==","user":{"login":"ckknight","id":66227,"node_id":"MDQ6VXNlcjY2MjI3","avatar_url":"https://avatars1.githubusercontent.com/u/66227?v=4","gravatar_id":"","url":"https://api.github.com/users/ckknight","html_url":"https://github.com/ckknight","followers_url":"https://api.github.com/users/ckknight/followers","following_url":"https://api.github.com/users/ckknight/following{/other_user}","gists_url":"https://api.github.com/users/ckknight/gists{/gist_id}","starred_url":"https://api.github.com/users/ckknight/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ckknight/subscriptions","organizations_url":"https://api.github.com/users/ckknight/orgs","repos_url":"https://api.github.com/users/ckknight/repos","events_url":"https://api.github.com/users/ckknight/events{/privacy}","received_events_url":"https://api.github.com/users/ckknight/received_events","type":"User","site_admin":false},"created_at":"2018-06-15T02:31:04Z","updated_at":"2018-06-15T02:31:04Z","author_association":"NONE","body":"This might be what you're going for:\r\n\r\n```ts\r\ndeclare function bind<H extends any[], T extends any[], R>(\r\n  fn:  (...args: [...H, ...T]), ...args: H\r\n): (...t: T) => R\r\n```"}}
{"actor":{"display_login":"ckknight"}}