Title: Mapping a generic type should again result in a generic type · Issue #48036 · microsoft/TypeScript · GitHub
Open Graph Title: Mapping a generic type should again result in a generic type · Issue #48036 · microsoft/TypeScript
X Title: Mapping a generic type should again result in a generic type · Issue #48036 · microsoft/TypeScript
Description: Suggestion 🔍 Search Terms mapped type type mapping generics generic function unknown ✅ Viability Checklist My suggestion meets these guidelines: This wouldn't be a breaking change in existing TypeScript/JavaScript code This wouldn't chan...
Open Graph Description: Suggestion 🔍 Search Terms mapped type type mapping generics generic function unknown ✅ Viability Checklist My suggestion meets these guidelines: This wouldn't be a breaking change in existing TypeS...
X Description: Suggestion 🔍 Search Terms mapped type type mapping generics generic function unknown ✅ Viability Checklist My suggestion meets these guidelines: This wouldn't be a breaking change in existing T...
Opengraph URL: https://github.com/microsoft/TypeScript/issues/48036
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Mapping a generic type should again result in a generic type","articleBody":"# Suggestion\r\n\r\n## 🔍 Search Terms\r\n\r\n* mapped type\r\n* type mapping\r\n* generics\r\n* generic function\r\n* unknown \r\n\r\n## ✅ Viability Checklist\r\n\r\nMy suggestion meets these guidelines:\r\n\r\n* [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code\r\n* [x] This wouldn't change the runtime behavior of existing JavaScript code\r\n* [x] This could be implemented without emitting different JS based on the types of the expressions\r\n* [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)\r\n* [x] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).\r\n\r\n## ⭐ Suggestion\r\n\r\nPerforming type mapping on a generic type should result in a new generic type with that mapping applied, rather than a concrete type with `unknown` in place of generics.\r\n\r\n## 📃 Motivating Example\r\n\r\nConsider the following utility type `Async\u003cT\u003e`. It takes an arbitrary function signature and returns the signature of an equivalent asynchronous function.\r\n\r\n```ts\r\ntype Async\u003cT extends (...args: any) =\u003e any\u003e = T extends (...args: infer Args) =\u003e infer Result\r\n ? (...args: Args) =\u003e Promise\u003cResult\u003e\r\n : never;\r\n\r\ntype SimpleFunction = (arg: number) =\u003e string;\r\ntype AsyncSimpleFunction = Async\u003cSimpleFunction\u003e;\r\n// result: (arg: number) =\u003e Promise\u003cstring\u003e ✅\r\n```\r\n\r\nNow let's give it a generic function:\r\n\r\n```ts\r\ntype GenericFunction1 = \u003cT\u003e(arg: T) =\u003e string;\r\ntype AsyncGenericFunction1 = Async\u003cGenericFunction1\u003e;\r\n// expected: \u003cT\u003e(arg: T) =\u003e Promise\u003cstring\u003e\r\n// actual: (arg: unknown) =\u003e Promise\u003cstring\u003e ⛔️\r\n\r\ntype GenericFunction2 = \u003cT\u003e(arg: number) =\u003e T;\r\ntype AsyncGenericFunction2 = Async\u003cGenericFunction2\u003e;\r\n// expected: \u003cT\u003e(arg: number) =\u003e Promise\u003cT\u003e\r\n// actual: (arg: number) =\u003e Promise\u003cunknown\u003e ⛔️\r\n```\r\n\r\nAs this example shows, we cannot use the helper type `Async\u003cT\u003e` with a generic function signature. If we try, we get a non-generic function signature with `unknown` wherever a generic argument was used.\r\n\r\n## 💻 Use Cases\r\n\r\nWe maintain a plugin system. Plugins are developed against a carefully designed API. For every type in the plugin API, there is a corresponding internal type. Plugin values and internal values are identical at runtime, but their types differ. For instance, the same concept may be represented by a class internally, but by a branded interface towards the plugins.\r\n\r\nTo convert between an internal type and its corresponding plugin type, we use a recursive mapped type. This words great, *unless* the value is (or contains) a generic function.","author":{"url":"https://github.com/DanielSWolf","@type":"Person","name":"DanielSWolf"},"datePublished":"2022-02-25T11:11:25.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":3},"url":"https://github.com/48036/TypeScript/issues/48036"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:76cb5ff6-96e4-5783-5906-14c5b79b349a |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 85E6:13928A:443E63:5F742F:6A6238C9 |
| html-safe-nonce | 4b93e9a73ec2005d6e8d0d75ebb1352653a7626b98b41aee81f8f95a5488bf11 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI4NUU2OjEzOTI4QTo0NDNFNjM6NUY3NDJGOjZBNjIzOEM5IiwidmlzaXRvcl9pZCI6IjM3MTY0NTg4MzgyMTg2NTE4NDkiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | 79876c4e65c3a0fe1f5d66f3bc464f1a10be2f5785973fb54e6286d47bcd9ea3 |
| hovercard-subject-tag | issue:1150325095 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/microsoft/TypeScript/48036/issue_layout |
| twitter:image | https://opengraph.githubassets.com/fec4aa086d3904e2d04ace2d340b9e18bfe7dd1c649b339202b997d8a914d72f/microsoft/TypeScript/issues/48036 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/fec4aa086d3904e2d04ace2d340b9e18bfe7dd1c649b339202b997d8a914d72f/microsoft/TypeScript/issues/48036 |
| og:image:alt | Suggestion 🔍 Search Terms mapped type type mapping generics generic function unknown ✅ Viability Checklist My suggestion meets these guidelines: This wouldn't be a breaking change in existing TypeS... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | DanielSWolf |
| hostname | github.com |
| expected-hostname | github.com |
| None | 81a21eb42fd0e80f3094d5be0f523bc284f5792af0333a266ecada0c39501f0f |
| turbo-cache-control | no-preview |
| go-import | github.com/microsoft/TypeScript git https://github.com/microsoft/TypeScript.git |
| octolytics-dimension-user_id | 6154722 |
| octolytics-dimension-user_login | microsoft |
| octolytics-dimension-repository_id | 20929025 |
| octolytics-dimension-repository_nwo | microsoft/TypeScript |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 20929025 |
| octolytics-dimension-repository_network_root_nwo | microsoft/TypeScript |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 76f36d3a9c09a237d489d4eeeaf6db0b604da73f |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width