Gathering detailed insights and metrics for core-decorators
Gathering detailed insights and metrics for core-decorators
Gathering detailed insights and metrics for core-decorators
Gathering detailed insights and metrics for core-decorators
lodash-decorators
A collection of decorators using lodash at it's core.
@types/core-decorators
Stub TypeScript definitions entry for core-decorators.js, which provides its own types definitions
ts-core-decorators
typescript core decorators
@type-cacheable/core
TypeScript-based caching decorators
Library of stage-0 JavaScript decorators (aka ES2016/ES7 decorators but not accurate) inspired by languages that come with built-ins like @override, @deprecate, @autobind, @mixin and more. Popular with React/Angular, but is framework agnostic.
npm install core-decorators
Typescript
Module System
Node Version
NPM Version
JavaScript (99.87%)
TypeScript (0.13%)
Total Downloads
25,731,184
Last Day
8,127
Last Week
39,098
Last Month
195,140
Last Year
3,009,499
MIT License
4,517 Stars
253 Commits
262 Forks
74 Watchers
27 Branches
22 Contributors
Updated on May 07, 2025
Latest Version
0.20.0
Package Id
core-decorators@0.20.0
Size
45.00 kB
NPM Version
4.1.2
Node Version
7.7.1
Published on
Sep 03, 2017
Cumulative downloads
Total Downloads
Last Day
-5.2%
8,127
Compared to previous day
Last Week
-19.9%
39,098
Compared to previous week
Last Month
-2.9%
195,140
Compared to previous month
Last Year
-25.2%
3,009,499
Compared to previous year
24
Library of JavaScript stage-0 decorators (aka ES2016/ES7 decorators but that's not accurate) inspired by languages that come with built-ins like @override, @deprecate, @autobind, @mixin and more. Popular with React/Angular, but is framework agnostic. Similar to Annotations in Java but unlike Java annotations, decorators are functions which are applied at runtime.
These are stage-0 decorators because while the decorators spec has changed and is now stage-2, no transpiler has yet to implement these changes and until they do, this library won't either. Although the TypeScript documentation uses the phrase "Decorators are a stage 2 proposal for JavaScript" this is misleading because TypeScript still only implements the stage-0 version of the spec, which is very incompatible with stage-2 (as of this writing). If you concretely find that a compiler (babel, TS, etc) implement stage-2+, please do link me to the appropriate release notes! :balloon:
*compiled code is intentionally not checked into this repo
A version compiled to ES5 in CJS format is published to npm as core-decorators
1npm install core-decorators --save
This can be consumed by any transpiler that supports stage-0 of the decorators spec, like babel.js version 5. Babel 6 does not yet support decorators natively, but you can include babel-plugin-transform-decorators-legacy or use the applyDecorators()
helper.
core-decorators does not officially support TypeScript. There are known incompatibilities with the way it transpiles the output. PRs certainly welcome to fix that!
A globals version is available here in the artifact repo, or via $ bower install core-decorators
. It defines a global variable CoreDecorators
, which can then be used as you might expect: @CoreDecorators.autobind()
, etc.
I highly recommend against using that globals build as it's quite strange you're using decorators (a proposed future feature of JavaScript) while not using ES2015 modules, a spec ratified feature used by nearly every modern framework. Also--bower is on its deathbed and IMO for very good reasons.
core-decorators aims to provide decorators that are fundamental to JavaScript itself--mostly things you could do with normal Object.defineProperty
but not as easily when using ES2015 classes. Things like debouncing, throttling, and other more opinionated decorators are being phased out in favor of lodash-decorators which wraps applicable lodash utilities as decorators. We don't want to duplicate the effort of lodash, which has years and years of robust testing and bugfixes.
Note: there is a bug in
react-hot-loader <= 1.3.0
(they fixed in2.0.0-alpha-4
) which prevents this from working as expected. Follow it here
Forces invocations of this function to always have this
refer to the class instance, even if the function is passed around or would otherwise lose its this
context. e.g. var fn = context.method;
Popular with React components.
Individual methods:
1import { autobind } from 'core-decorators'; 2 3class Person { 4 @autobind 5 getPerson() { 6 return this; 7 } 8} 9 10let person = new Person(); 11let { getPerson } = person; 12 13getPerson() === person; 14// true
Entire Class:
1import { autobind } from 'core-decorators'; 2 3@autobind 4class Person { 5 getPerson() { 6 return this; 7 } 8 9 getPersonAgain() { 10 return this; 11 } 12} 13 14let person = new Person(); 15let { getPerson, getPersonAgain } = person; 16 17getPerson() === person; 18// true 19 20getPersonAgain() === person; 21// true
Marks a property or method as not being writable.
1import { readonly } from 'core-decorators'; 2 3class Meal { 4 @readonly 5 entree = 'steak'; 6} 7 8var dinner = new Meal(); 9dinner.entree = 'salmon'; 10// Cannot assign to read only property 'entree' of [object Object] 11
Checks that the marked method indeed overrides a function with the same signature somewhere on the prototype chain.
Works with methods and getters/setters only (not property initializers/arrow functions). Will ensure name, parameter count, as well as descriptor type (accessor/data). Provides a suggestion if it finds a method with a similar signature, including slight misspellings.
1import { override } from 'core-decorators'; 2 3class Parent { 4 speak(first, second) {} 5} 6 7class Child extends Parent { 8 @override 9 speak() {} 10 // SyntaxError: Child#speak() does not properly override Parent#speak(first, second) 11} 12 13// or 14 15class Child extends Parent { 16 @override 17 speaks() {} 18 // SyntaxError: No descriptor matching Child#speaks() was found on the prototype chain. 19 // 20 // Did you mean "speak"? 21}
Calls console.warn()
with a deprecation message. Provide a custom message to override the default one. You can also provide an options hash with a url
, for further reading.
1import { deprecate } from 'core-decorators'; 2 3class Person { 4 @deprecate 5 facepalm() {} 6 7 @deprecate('We stopped facepalming') 8 facepalmHard() {} 9 10 @deprecate('We stopped facepalming', { url: 'http://knowyourmeme.com/memes/facepalm' }) 11 facepalmHarder() {} 12} 13 14let person = new Person(); 15 16person.facepalm(); 17// DEPRECATION Person#facepalm: This function will be removed in future versions. 18 19person.facepalmHard(); 20// DEPRECATION Person#facepalmHard: We stopped facepalming 21 22person.facepalmHarder(); 23// DEPRECATION Person#facepalmHarder: We stopped facepalming 24// 25// See http://knowyourmeme.com/memes/facepalm for more details. 26//
Creates a new debounced function which will be invoked after wait
milliseconds since the time it was invoked. Default timeout is 300 ms.
Optional boolean second argument allows to trigger function on the leading instead of the trailing edge of the wait interval. Implementation is inspired by similar method from UnderscoreJS.
1import { debounce } from 'core-decorators'; 2 3class Editor { 4 5 content = ''; 6 7 @debounce(500) 8 updateContent(content) { 9 this.content = content; 10 } 11}
Creates a new throttled function which will be invoked in every wait
milliseconds. Default timeout is 300 ms.
Second argument is optional options:
leading
: default to true
, allows to trigger function on the leading.trailing
: default to true
, allows to trigger function on the trailing edge of the wait interval.Implementation is inspired by similar method from UnderscoreJS.
1import { throttle } from 'core-decorators'; 2 3class Editor { 4 5 content = ''; 6 7 @throttle(500, {leading: false}) 8 updateContent(content) { 9 this.content = content; 10 } 11}
Suppresses any JavaScript console.warn()
call while the decorated function is called. (i.e. on the stack)
Will not suppress warnings triggered in any async code within.
1import { suppressWarnings } from 'core-decorators'; 2 3class Person { 4 @deprecated 5 facepalm() {} 6 7 @suppressWarnings 8 facepalmWithoutWarning() { 9 this.facepalm(); 10 } 11} 12 13let person = new Person(); 14 15person.facepalmWithoutWarning(); 16// no warning is logged
Marks a method as being enumerable. Note that instance properties are already enumerable, so this is only useful for methods.
1import { enumerable } from 'core-decorators'; 2 3class Meal { 4 pay() {} 5 6 @enumerable 7 eat() {} 8} 9 10var dinner = new Meal(); 11for (var key in dinner) { 12 key; 13 // "eat" only, not "pay" 14} 15
Marks a property as not being enumerable. Note that class methods are already nonenumerable, so this is only useful for instance properties.
1import { nonenumerable } from 'core-decorators'; 2 3class Meal { 4 entree = 'steak'; 5 6 @nonenumerable 7 cost = 20.99; 8} 9 10var dinner = new Meal(); 11for (var key in dinner) { 12 key; 13 // "entree" only, not "cost" 14} 15 16Object.keys(dinner); 17// ["entree"] 18
Marks a property or method so that it cannot be deleted; also prevents it from being reconfigured via Object.defineProperty
, but this may not always work how you expect due to a quirk in JavaScript itself, not this library. Adding the @readonly
decorator fixes it, but at the cost of obviously making the property readonly (aka writable: false
). You can read more about this here.
1import { nonconfigurable } from 'core-decorators'; 2 3class Foo { 4 @nonconfigurable 5 @readonly 6 bar() {}; 7} 8 9Object.defineProperty(Foo.prototype, 'bar', { 10 value: 'I will error' 11}); 12// Cannot redefine property: bar 13
Immediately applies the provided function and arguments to the method, allowing you to wrap methods with arbitrary helpers like those provided by lodash. The first argument is the function to apply, all further arguments will be passed to that decorating function.
1import { decorate } from 'core-decorators'; 2import { memoize } from 'lodash'; 3 4var count = 0; 5 6class Task { 7 @decorate(memoize) 8 doSomethingExpensive(data) { 9 count++; 10 // something expensive; 11 return data; 12 } 13} 14 15var task = new Task(); 16var data = [1, 2, 3]; 17 18task.doSomethingExpensive(data); 19task.doSomethingExpensive(data); 20 21count === 1; 22// true
Prevents a property initializer from running until the decorated property is actually looked up. Useful to prevent excess allocations that might otherwise not be used, but be careful not to over-optimize things.
1import { lazyInitialize } from 'core-decorators'; 2 3function createHugeBuffer() { 4 console.log('huge buffer created'); 5 return new Array(1000000); 6} 7 8class Editor { 9 @lazyInitialize 10 hugeBuffer = createHugeBuffer(); 11} 12 13var editor = new Editor(); 14// createHugeBuffer() has not been called yet 15 16editor.hugeBuffer; 17// logs 'huge buffer created', now it has been called 18 19editor.hugeBuffer; 20// already initialized and equals our buffer, so 21// createHugeBuffer() is not called again
Mixes in all property descriptors from the provided Plain Old JavaScript Objects (aka POJOs) as arguments. Mixins are applied in the order they are passed, but do not override descriptors already on the class, including those inherited traditionally.
1import { mixin } from 'core-decorators'; 2 3const SingerMixin = { 4 sing(sound) { 5 alert(sound); 6 } 7}; 8 9const FlyMixin = { 10 // All types of property descriptors are supported 11 get speed() {}, 12 fly() {}, 13 land() {} 14}; 15 16@mixin(SingerMixin, FlyMixin) 17class Bird { 18 singMatingCall() { 19 this.sing('tweet tweet'); 20 } 21} 22 23var bird = new Bird(); 24bird.singMatingCall(); 25// alerts "tweet tweet" 26
Uses console.time
and console.timeEnd
to provide function timings with a unique label whose default prefix is ClassName.method
. Supply a first argument to override the prefix:
1class Bird { 2 @time('sing') 3 sing() { 4 } 5} 6 7var bird = new Bird(); 8bird.sing(); // console.time label will be 'sing-0' 9bird.sing(); // console.time label will be 'sing-1'
Will polyfill console.time
if the current environment does not support it. You can also supply a custom console
object as the second argument with the following methods:
myConsole.time(label)
myConsole.timeEnd(label)
myConsole.log(value)
1let myConsole = { 2 time: function(label) { /* custom time() method */ }, 3 timeEnd: function(label) { /* custom timeEnd method */ }, 4 log: function(str) { /* custom log method */ } 5}
Uses console.profile
and console.profileEnd
to provide function profiling with a unique label whose default prefix is ClassName.method
. Supply a first argument to override the prefix:
1class Bird { 2 @profile('sing') 3 sing() { 4 } 5} 6 7var bird = new Bird(); 8bird.sing(); // Adds a profile with label sing and marked as run 1 9bird.sing(); // Adds a profile with label sing and marked as run 2
Because profiling is expensive, you may not want to run it every time the function is called. Supply a second argument of true
to have the profiling only run once:
1class Bird { 2 @profile(null, true) 3 sing() { 4 } 5} 6 7var bird = new Bird(); 8bird.sing(); // Adds a profile with label Bird.sing 9bird.sing(); // Does nothing
Alternatively you can pass a number instead of true
to represent the milliseconds between profiles. Profiling is always ran on the leading edge.
1class Bird { 2 @profile(null, 1000) 3 sing() { 4 } 5} 6 7var bird = new Bird(); 8bird.sing(); // Adds a profile with label Bird.sing 9// Wait 100ms 10bird.sing(); // Does nothing 11// Wait 1000ms 12bird.sing(); // Adds a profile with label Bird.sing
When you need extremely fine-tuned control, you can pass a function that returns a boolean to determine if profiling should occur. The function will have this
context of the instance and the arguments to the method will be passed to the function as well. Arrow functions will not receive the instance context.
1class Bird { 2 @profile(null, function (volume) { return volume === 'loud'; }) 3 sing(volume) { 4 } 5 6 @profile(null, function () { return this.breed === 'eagle' }) 7 fly() { 8 } 9} 10 11var bird = new Bird(); 12bird.sing('loud'); // Adds a profile with label Bird.sing 13bird.sing('quite'); // Does nothing 14 15bird.fly(); // Does nothing 16bird.breed = 'eagle'; 17bird.fly(); // Adds a profile with label Bird.fly
Profiling is currently only supported in Chrome 53+, Firefox, and Edge. Unfortunately this feature can't be polyfilled or faked, so if used in an unsupported browser or Node.js then this decorator will automatically disable itself.
Extends the new property descriptor with the descriptor from the super/parent class prototype. Although useful in various circumstances, it's particularly helpful to address the fact that getters and setters share a single descriptor so overriding only a getter or only a setter will blow away the other, without this decorator.
1class Base { 2 @nonconfigurable 3 get foo() { 4 return `hello ${this._foo}`; 5 } 6} 7 8class Derived extends Base { 9 @extendDescriptor 10 set foo(value) { 11 this._foo = value; 12 } 13} 14 15const derived = new Derived(); 16derived.foo = 'bar'; 17derived.foo === 'hello bar'; 18// true 19 20const desc = Object.getOwnPropertyDescriptor(Derived.prototype, 'foo'); 21desc.configurable === false; 22// true
The applyDecorators()
helper can be used when you don't have language support for decorators like in Babel 6 or even with vanilla ES5 code without a transpiler.
1class Foo {
2 getFoo() {
3 return this;
4 }
5}
6
7// This works on regular function prototypes
8// too, like `function Foo() {}`
9applyDecorators(Foo, {
10 getFoo: [autobind]
11});
12
13let foo = new Foo();
14let getFoo = foo.getFoo;
15getFoo() === foo;
16// true
Since most people can't keep up to date with specs, it's important to note that the spec is in-flux and subject to breaking changes. For the most part, these changes will probably be transparent to consumers of this project--that said, core-decorators has not yet reached 1.0 and may in fact introduce breaking changes. If you'd prefer not to receive these changes, be sure to lock your dependency to PATCH. You can track the progress of core-decorators@1.0.0 in the The Road to 1.0 ticket.
When using multiple decorators on a class, method, or property the order of the decorators sometimes matters. This is a neccesary caveat of decorators because otherwise certain cool features wouldn't be possible. The most common example of this is using @autobind
and any Higher-Order Component (HOC) decorator, e.g. Redux's @connect
. You must @autobind
your class first before applying the @connect
HOC.
1@connect() 2@autobind 3class Foo extends Component {}
No vulnerabilities found.
No security vulnerabilities found.