Title: RFC: Support __proto__ literal in object initializers · Issue #38385 · microsoft/TypeScript · GitHub
Open Graph Title: RFC: Support __proto__ literal in object initializers · Issue #38385 · microsoft/TypeScript
X Title: RFC: Support __proto__ literal in object initializers · Issue #38385 · microsoft/TypeScript
Description: This is a new issue to specifically propose and elaborate on a feature I raised in this comment on #30587. Search Terms __proto__ prototype object literal object spread object initializer Suggestion While accessing or mutating an existin...
Open Graph Description: This is a new issue to specifically propose and elaborate on a feature I raised in this comment on #30587. Search Terms __proto__ prototype object literal object spread object initializer Suggestio...
X Description: This is a new issue to specifically propose and elaborate on a feature I raised in this comment on #30587. Search Terms __proto__ prototype object literal object spread object initializer Suggestio...
Opengraph URL: https://github.com/microsoft/TypeScript/issues/38385
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"RFC: Support __proto__ literal in object initializers","articleBody":"This is a new issue to specifically propose and elaborate on a feature I raised [in this comment](https://github.com/microsoft/TypeScript/issues/30587#issuecomment-614855795) on #30587.\r\n\r\n## Search Terms\r\n\r\n- \\_\\_proto__\r\n- prototype\r\n- object literal\r\n- object spread\r\n- object initializer\r\n\r\n## Suggestion\r\nWhile accessing or mutating an _existing_ object via the `Object.protptype.__proto__` getter/setter is deprecated, to the best of my knowledge defining the prototype of a _new_ object via the object initializer `__proto__` literal is very much encouraged.\r\n\r\nThe rules for specifying the prototype of a new object via these semantics are very well-specified and safe. [See the relevant section of the spec here.](https://www.ecma-international.org/ecma-262/6.0/index.html#sec-__proto__-property-names-in-object-initializers)\r\n\r\n\r\n### Basic support\r\nGiven the following:\r\n```ts\r\nconst foo = {\r\n __proto__: { a: \"a\" },\r\n b: \"b\"\r\n};\r\n```\r\n\r\nTypescript currently thinks that `foo` is the following shape:\r\n```ts\r\ntype foo = {\r\n [\"__proto__\"]: { a: string };\r\n b: string;\r\n};\r\n```\r\n\r\nwhen in reality, it is:\r\n```ts\r\ntype foo = {\r\n a: string;\r\n b: string;\r\n};\r\n```\r\n\r\nTypeScript should be able to correctly detect the type of this object initialization.\r\n\r\n### Strict validity checks\r\nAdditionally, TypeScript should prevent invalid `__proto__` assignments that are \"ignored\" by the spec, and require all values to be `null` or an object. This should fail validation:\r\n\r\n```ts\r\nconst invalid = { __proto__: \"hello\" }\r\n```\r\n\r\n### Correct handling of computed properties\r\n\r\nIt's important to note that per the spec, `__proto__` literals are _not_ the same as regular property assignments.\r\n\r\nThis object initialization, for example:\r\n\r\n```ts\r\nconst foo = {\r\n __proto__: { a: \"a\" },\r\n b: \"b\",\r\n [\"__proto__\"]: { c: \"c\"},\r\n};\r\n```\r\ncreates an object of the following shape:\r\n```ts\r\ntype foo = {\r\n a: string;\r\n b: string;\r\n [\"__proto__\"]: { c: string};\r\n};\r\n```\r\n\r\nGiven this, I would recommend that a `__proto__` literal be forbidden in _type/interface definitions_, such that this is considered a syntax error:\r\n```ts\r\ntype foo = {\r\n __proto__: { a: string }\r\n}\r\n```\r\nwhile this is an allowable way to specify a **property** named `__proto__` on the type `foo`.\r\n```ts\r\ntype foo = {\r\n [\"__proto__\"]: string\r\n}\r\n```\r\n\r\n## Use-Cases \u0026 Examples\r\n\r\nThis feature allows TypeScript to correctly understand the shape of objects defined with standard JS semantics. While this pattern isn't especially prevalent, it is an important feature of the language, and should be much more common in one particular use-case where TypeScript currently has a rather severe blind spot:\r\n\r\nTypeScript currently _PREVENTS_ the creation of safe indexed objects derived from existing indexed objects. For example:\r\n\r\nGiven this object, and the goal of \"spreading\" it into a new map:\r\n```ts\r\n// All safe map objects MUST have a `null` prototype.\r\nconst someMapObject: { [key: string]: boolean } = Object.create(null);\r\n```\r\n\r\nThe following is UNSAFE, and probably the most common approach I see people using. TypeScript _should_ catch this, and _should_ issue a compile-time error. See bug #37963. \r\n\r\n```ts\r\nconst unsafeSpreadMapObject: { [key: string]: boolean | undefined } = {\r\n ...someMapObject,\r\n foo: false\r\n};\r\n\r\nconsole.log(typeof unsafeSpreadMapObject[\"constructor\"]);\r\n// =\u003e function\r\n\r\nconsole.log(typeof safeSpreadMapObject[\"foo\"]);\r\n// =\u003e boolean\r\n```\r\n\r\nThe following is also UNSAFE. While using `Object.assign` and `Object.create` is a perfectly valid alternative, the `any` returned by `Object.create` propagates through the statement and breaks type safety. (Perhaps the result of `Object.create` should be `unknown` instead of `any`?)\r\n\r\n```ts\r\nconst unsafeAssignMapObject: { [key: string]: boolean | undefined } = Object.assign(\r\n Object.create(null),\r\n { foo: \"this is not boolean\" }\r\n);\r\n\r\nconsole.log(typeof safeSpreadMapObject[\"constructor\"]);\r\n// =\u003e undefined\r\n\r\nconsole.log(typeof safeSpreadMapObject[\"foo\"]);\r\n// =\u003e string\r\n```\r\n\r\nThis is the SAFE way to accomplish this while using object spreads, but TypeScript currently forbids it, since it lacks support for the `__proto__` literal, and incorrectly believes a _property_ of type `null` is being defined:\r\n```ts\r\nconst safeSpreadMapObject: { [key: string]: boolean | undefined } = {\r\n __proto__: null,\r\n ...someMapObject,\r\n foo: false\r\n};\r\n\r\nconsole.log(typeof safeSpreadMapObject[\"constructor\"]);\r\n// =\u003e undefined\r\n\r\nconsole.log(typeof safeSpreadMapObject[\"foo\"]);\r\n// =\u003e boolean\r\n```\r\n\r\n\r\n## 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, 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\r\n## References\r\n- [Object initialization: Prototype mutation (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Prototype_mutation)\r\n- [\\_\\_proto__ Property Names in Object Initializers (ECMAScript Spec)](https://tc39.es/ecma262/#sec-__proto__-property-names-in-object-initializers)","author":{"url":"https://github.com/mike-marcacci","@type":"Person","name":"mike-marcacci"},"datePublished":"2020-05-07T04:43:16.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":17},"url":"https://github.com/38385/TypeScript/issues/38385"}
| 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:d11f5018-3b31-29a8-d6ec-eb2b5f651a1a |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | AFD4:3F6EBB:17B904:1F902D:6A4D85A6 |
| html-safe-nonce | 0eef2bb4c544f51a7ca424dc57447a7c2de64c7e7ea0fea18cf26c903a227298 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJBRkQ0OjNGNkVCQjoxN0I5MDQ6MUY5MDJEOjZBNEQ4NUE2IiwidmlzaXRvcl9pZCI6IjI4NTU1MjkzNzUyNjM5ODMwMTUiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | 36ed456c4fddde55e4123e4ca957ab810e3339d7e3c362c3da867067a155bc52 |
| hovercard-subject-tag | issue:613768265 |
| 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/38385/issue_layout |
| twitter:image | https://opengraph.githubassets.com/4a7a35e4463c3d078ef58ec2696167a1409f0d3c27ae6cbdac0c575868d81f2b/microsoft/TypeScript/issues/38385 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/4a7a35e4463c3d078ef58ec2696167a1409f0d3c27ae6cbdac0c575868d81f2b/microsoft/TypeScript/issues/38385 |
| og:image:alt | This is a new issue to specifically propose and elaborate on a feature I raised in this comment on #30587. Search Terms __proto__ prototype object literal object spread object initializer Suggestio... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | mike-marcacci |
| hostname | github.com |
| expected-hostname | github.com |
| None | 9f8758a3953dfe943439713a6fa4f90d542a3431f10e861ca03dd7f39009f320 |
| 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 | bffd5484f01713a661b03469b77678f72b6574ed |
| ui-target | canary-1 |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width