Repository navigation
Partial support decorators when targeting ES3 #4681
Description
Activity
- changed the title
[-]Partially support decorators when targeting ES3[/-][+]Partial support decorators when targeting ES3[/+]on Sep 7, 2015 The problem is the
__decoratehelper uses ES5 features likereduceRight. so any proposal here would need to address that as well.- addedNeeds ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.This issue needs a plan that clarifies the finer details of how it could be implemented.
on Sep 8, 2015 TypeScript does not emit, or depend on any polyfills. if you do for your code, and include polyfills you manage them separately. for helper code emitted by the compiler there is no dependency on any polyfills currently, nor this is intended.
__decoratehelper will be emitted in every file that uses decorators. we try to keep any helper code as small as and as efficient as possible, since we are polluting user code.Also we do not emit different versions of the helpers based on the target, to avoid breaking user code from an imported library built with a different target, but loaded first.
so a proposal for this should include the shape of the
__decoratethat does not usereduceRight, which will either be a for loop with a call to function, or a call to an additional helper function.Personally, i would say the shape the helper is important, as again we emit it in every file. and since day 1, typescript strives to emit clean, idiomatic, JavaScript that would looks like the code you would write by hand if you were not using a compiler.
Proposal for
__decoratehelper withoutreduceRight:var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc); for (var i = decorators.length - 1, d, r; i >= 0; i--) if (d = decorators[i]) switch (arguments.length) { case 2: r = target = d(target) || target; break; case 3: d(target, key); break; case 4: r = desc = d(target, key, desc) || desc; break; } return r; };
This version is a bit shorter than the standard helper:)
More safe version (always returns the result, even if
decoratorsis an empty array):var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc); for (var i = decorators.length - 1, d; i >= 0; i--) if (d = decorators[i]) switch (arguments.length) { case 2: target = d(target) || target; break; case 3: d(target, key); break; case 4: desc = d(target, key, desc) || desc; break; } return desc || target; };
Mohamed Hegazy (@mhegazy) What do you think? Is it ok?
Ron Buckton (@rbuckton) any comments?
Koloto We initially did something similar, but simplified the
__decoratehelper when we decided to only support decorators for ES5+.If we do decide to support ES3, we would likely support method decorators in the same fashion as property decorators (e.g. without the property descriptor).
I tweaked Koloto's version a bit to avoid repeated lookups on arguments.length and adjusted the return value:
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc); for (var i = decorators.length - 1, argc = arguments.length, d; i >= 0; i--) if (d = decorators[i]) switch (argc) { case 2: target = d(target) || target; break; case 3: d(target, key); break; case 4: desc = d(target, key, desc) || desc; break; } if (argc !== 3) return desc || target; };
Further reduced:
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc); for (var i = decorators.length - 1, c = arguments.length, r = c < 3 ? target : desc, d; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : void d(target, key)) || r; return r; };
If we do decide to support ES3, we would likely support method decorators in the same fashion as property decorators (e.g. without the property descriptor).
It would be great to support method decorators in ES3 also. Can I hope to see this feature in v1.6? :) I suppose, no. But support just class and property decorators in ES3 seems much easier. It would be a good start.
This should be addressed as of #4741.
Decorators are now allowed when targeting ES3. In this case, all decorators on members of a class are treated in the same fashion as a decorator on a property declaration. A descriptor for the declaration will neither be provided to nor consumed by the
__decoratehelper in this case.Decorators for ES5 and higher should be unaffected (although the actual emit for each decorator has changed slightly).
- addedFixedA PR has been merged for this issueA PR has been merged for this issueand removedNeeds ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.This issue needs a plan that clarifies the finer details of how it could be implemented.
on Oct 3, 2015 - locked and limited conversation to collaborators
on Jun 19, 2018
Method/accessor decorators use
definePropertyandgetOwnPropertyDescriptor, which are not allowed in ES3. But class and property decorators don't use them. So class/property decorators can be allowed when targeting ES3.It would be helpful. E.g. I must support old browsers and I use the property like methods instead of pure properties:
I have the factory function that creates such method:
Currently I have to set such properties in the class prototype explicitly:
With decorators I could write more cleaner code:
Also there is no need to duplicate the property name (
"value"in the example above).