Title: Field declarations overwrite properties on the prototype · Issue #151 · tc39/proposal-class-fields · GitHub
Open Graph Title: Field declarations overwrite properties on the prototype · Issue #151 · tc39/proposal-class-fields
X Title: Field declarations overwrite properties on the prototype · Issue #151 · tc39/proposal-class-fields
Description: I think this issue has been raised a few times already in several of the open issues, like #100, but I thought it would probably be good to report a very specific, real life use case. The following snippet is the official way to enhance ...
Open Graph Description: I think this issue has been raised a few times already in several of the open issues, like #100, but I thought it would probably be good to report a very specific, real life use case. The following...
X Description: I think this issue has been raised a few times already in several of the open issues, like #100, but I thought it would probably be good to report a very specific, real life use case. The following...
Opengraph URL: https://github.com/tc39/proposal-class-fields/issues/151
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Field declarations overwrite properties on the prototype","articleBody":"I think this issue has been raised a few times already in several of the open issues, like #100, but I thought it would probably be good to report a very specific, real life use case. \r\n\r\nThe following snippet is the official way to enhance a class with observable capabalities in [MobX](https://github.com/mobxjs/mobx), when decorator syntax is not used. (See [`decorate` docs](https://mobx.js.org/refguide/api.html#-decorate))\r\n\r\n```javascript\r\nclass Counter {\r\n counter = 0\r\n}\r\n\r\ndecorate(Counter, { counter: observable })\r\n```\r\n\r\nWhich is currently semantically equivalent to:\r\n\r\n```javascript\r\nclass Counter {\r\n @observable counter = 0\r\n}\r\n```\r\n\r\nThis first example works fine with TypeScript and [babel-plugin-proposal-class-properties](https://babeljs.io/docs/en/next/babel-plugin-proposal-class-properties.html), but only if `loose` mode is used (that translates the initializes to an assignment in the constructor). In standards mode, this mechanism no longer works. \r\n\r\nThe simple reason is, the `decorate` call introduces the `count` property on the `Counter` property, and gives it a getter and setter. If just an assignment is made in the constructor, this works fine. However, if a new property is introduces, the property on the prototype is completely ignored and a new one is introduced on the instance. \r\n\r\nIn pseudo code `decorate` does something along these lines: \r\n\r\n```javascript\r\nclass Counter {\r\n counter = 3\r\n}\r\n\r\nObject.defineProperty(Counter.prototype, \"counter\", {\r\n set(counter) {\r\n this._counter = counter * 2 \r\n },\r\n get() {\r\n return this._counter * 2 \r\n }\r\n})\r\n\r\nconst counter = new Counter()\r\n\r\nconsole.log(counter.counter)\r\n```\r\n\r\nPrinting the `counter` will yield `12` in loose mode, but `3` in standards mode, as in standards mode the field would be re-introduced in a non-interceptable way.\r\n\r\n---\r\n\r\nI search this repo for it, but couldn't really find it, what was the motivation to change the spec in this regards? (or if it never changed; what is the motivation to deviate from what existing transpilers are doing?).\r\n\r\nAnd more specific: how could I express \"decorating\" my class fields in the future with the above API? After all, changing a prototype after the initial class declaration is not that uncommon in JavaScript. \r\n\r\n---\r\n\r\nA potentially future risk of this approach is that it will render MobX completely incompatible with create-react-app, if this proposal is finalized before the decorators standard, as the `decorate` utility is currently the only way in which CRA users can obtain decorator-like behavior without the syntax. For some background: https://mobx.js.org/best/decorators.html\r\n\r\nN.B. note that this problem also happens when the field is declared, but never initialized.\r\n\r\n---\r\n\r\n_Edit: for clarification to other readers of this issue, the difference in compilation between loose and standards mode is:_\r\n\r\n```javascript\r\n// Loose:\r\nvar Counter = function Counter() {\r\n this.x = 3 // assignment being picked up by property on the prototype\r\n}\r\n\r\n// Standard:\r\nvar Counter = function Counter() {\r\n Object.defineProperty(obj, \"counter\", { // Property definition hides prototype property\r\n value: 3,\r\n enumerable: true,\r\n configurable: true,\r\n writable: true\r\n });\r\n};\r\n```\r\n","author":{"url":"https://github.com/mweststrate","@type":"Person","name":"mweststrate"},"datePublished":"2018-10-17T19:31:16Z","url":"https://github.com/tc39/proposal-class-fields/issues/151"}
| react-profiling | 0 |
| react-import-map | react,react-dom,react-dom/client,react-dom/profiling,react-is,react-reconciler,react/compiler-runtime,react/jsx-dev-runtime,react/jsx-runtime,scheduler@d5750093facf |
| 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:2f8cff5f-1161-479f-ec81-652b3badd383 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | A60E:117B4D:2E6752:3F8A94:6AED7974 |
| html-safe-nonce | 2a3cb70b2e95e08960c83b039a158558e224d8bc38a93c24605ae26871d354bc |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJBNjBFOjExN0I0RDoyRTY3NTI6M0Y4QTk0OjZBRUQ3OTc0IiwidmlzaXRvcl9pZCI6IjY5OTcxNjExNDk0NTI0MzUwOCIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 7aab8d2c5443bc3b68cf1eb2c4d07ecb5195ab6be2c6694b68582c1f72e559b0 |
| hovercard-subject-tag | issue:371233558 |
| 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/tc39/proposal-class-fields/151/issue_layout |
| twitter:image | https://opengraph.githubassets.com/193c214c133cd142ed647ecb48601d51458ef41867bce9effe84b1d9ed28e553/tc39/proposal-class-fields/issues/151 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/193c214c133cd142ed647ecb48601d51458ef41867bce9effe84b1d9ed28e553/tc39/proposal-class-fields/issues/151 |
| og:image:alt | I think this issue has been raised a few times already in several of the open issues, like #100, but I thought it would probably be good to report a very specific, real life use case. The following... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | mweststrate |
| hostname | github.com |
| expected-hostname | github.com |
| None | 56fb42677ae87ed3e64410323d67980aa65d0485568a7858f874e7edfc6d1c11 |
| turbo-cache-control | no-preview |
| go-import | github.com/tc39/proposal-class-fields git https://github.com/tc39/proposal-class-fields.git |
| octolytics-dimension-user_id | 1725583 |
| octolytics-dimension-user_login | tc39 |
| octolytics-dimension-repository_id | 91250837 |
| octolytics-dimension-repository_nwo | tc39/proposal-class-fields |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 91250837 |
| octolytics-dimension-repository_network_root_nwo | tc39/proposal-class-fields |
| 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 | 9c9a37e2423ed382cf39f70b5aa4b4858b40a3b0 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
| react-app-name | issues |
Links:
Viewport: width=device-width