UNPKG

10.5 kBMarkdownView Raw
1# lodash-decorators
2
3Decorators using lodash functions. View the [API docs](https://steelsojka.github.io/lodash-decorators) for more in depth documentation.
4
5[![Build Status](https://travis-ci.org/steelsojka/lodash-decorators.svg)](https://travis-ci.org/steelsojka/lodash-decorators)
6[![npm version](https://badge.fury.io/js/lodash-decorators.svg)](http://badge.fury.io/js/lodash-decorators)
7
8<!-- START doctoc generated TOC please keep comment here to allow auto update -->
9<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
10
11
12- [Install](#install)
13 - [Polyfills](#polyfills)
14- [Usage](#usage)
15 - [Decorators](#decorators)
16 - [Example](#example)
17 - [Optional Params and Casing](#optional-params-and-casing)
18 - [Example](#example)
19 - [Partials](#partials)
20 - [Example](#example-1)
21 - [Composition](#composition)
22 - [Example](#example-2)
23 - [Instance Decorators](#instance-decorators)
24 - [Mixin](#mixin)
25 - [Example](#example-3)
26 - [Attempt](#attempt)
27 - [Example](#example-4)
28 - [Bind](#bind)
29 - [Example](#example-5)
30 - [Example](#example-6)
31 - [v4 Breaking Changes](#v4-breaking-changes)
32 - [Not all decorators can be applied to or forced on getters/setters.](#not-all-decorators-can-be-applied-to-or-forced-on-getterssetters)
33 - [No longer force instance decorator onto prototype](#no-longer-force-instance-decorator-onto-prototype)
34 - [All decorators now take arguments](#all-decorators-now-take-arguments)
35 - [Removal of extensions and validation package](#removal-of-extensions-and-validation-package)
36 - [Prototype decorator order no longer throws an error](#prototype-decorator-order-no-longer-throws-an-error)
37 - [Other breaking changes](#other-breaking-changes)
38 - [v4 Improvements](#v4-improvements)
39
40<!-- END doctoc generated TOC please keep comment here to allow auto update -->
41
42## Install
43
44`npm install --save lodash lodash-decorators`
45
46### Polyfills
47
48This library requires `Map` and `WeakMap` to be available globally. If `Map` or `WeakMap` is not supported in your environment then use a polyfill.
49
50## Usage
51
52For more in depth documentation please visit [Lodash](http://lodash.com/docs)
53
54Decorators are exported as both start case and lower case.
55
56`import { Debounce } from 'lodash-decorators';`
57
58is the same as
59
60`import { debounce } from 'lodash-decorators';`
61
62They can also be imported directly.
63
64`import Debounce from 'lodash-decorators/debounce';`
65
66### Decorators
67
68These decorators are included in the package. These are also exported as lowercase for those who prefer lowercase decorators.
69
70- `After`
71- `AfterAll`
72- `Ary`
73- `Attempt`
74- `Before`
75- `BeforeAll`
76- `Bind`
77- `BindAll`
78- `Curry`
79- `CurryAll`
80- `CurryRight`
81- `CurryRightAll`
82- `Debounce`
83- `DebounceAll`
84- `Defer`
85- `Delay`
86- `Flip`
87- `Flow`
88- `FlowRight`
89- `Memoize`
90- `MemoizeAll`
91- `Mixin`
92- `Negate`
93- `Once`
94- `OnceAll`
95- `OverArgs`
96- `Partial`
97- `PartialRight`
98- `Rearg`
99- `Rest`
100- `Spread`
101- `Tap`
102- `Throttle`
103- `ThrottleAll`
104- `ThrottleGetter`
105- `ThrottleSetter`
106- `Unary`
107- `Wrap`
108
109#### Example
110
111```javascript
112import { Debounce, Memoize } from 'lodash-decorators';
113
114class Person {
115 constructor(firstName, lastName) {
116 this.firstName = firstName;
117 this.lastName = lastName;
118 }
119
120 @Debounce(100)
121 save(date) {
122 return this.httpService.post(data);
123 }
124
125 @Memoize(item => item.id)
126 doSomeHeavyProcessing(arg1, arg2) {}
127}
128```
129
130### Optional Params and Casing
131
132If a decorator does not require params or has optional params then the decorator does not require invocation.
133Decorators are also exported in lower case as well as start case.
134
135#### Example
136
137```javascript
138// These are both valid decorator usages.
139class Person {
140 @Memoize()
141 doSomething() {}
142
143 @Memoize
144 doSomething2() {}
145
146 @memoize()
147 doSomething3() {}
148
149 @memoize
150 doSomething4() {}
151}
152```
153
154### Partials
155
156Some decorators work slightly differently than you would expect
157them to work than lodash.
158
159- `Partial`
160- `PartialRight`
161- `Wrap`
162
163These can take a `Function` as their first argument or a `String`.
164If the argument is a `String` then a `Function` is resolved from
165the current object.
166
167#### Example
168
169```javascript
170import { Partial, Wrap } from 'lodash-decorators'
171
172class Person {
173 constructor(firstName, lastName) {
174 this.firstName = firstName;
175 this.lastName = lastName;
176 }
177
178 getName(type) {
179 return type === 'firstName' ? this.firstName : this.lastName
180 }
181
182 @Partial('getName', 'firstName')
183 getFirstName() {}
184
185 @Partial('getName', null)
186 getLastName() {}
187
188 @Wrap('getName')
189 getUpperCaseName(fn) {
190 return fn().toUpperCase();
191 }
192}
193
194const person = new Person('Joe', 'Smith');
195
196person.getFirstName(); // 'Joe'
197person.getLastName(); // 'Smith'
198person.getUpperCaseName(); // JOE SMITH
199```
200
201### Composition
202
203You can use methods like `compose` and `flow` similiar to
204partials. The arguments are resolved the same way partials
205are resolved.
206
207#### Example
208
209```javascript
210import { Flow } from 'lodash-decorators'
211import { kebabCase } from 'lodash';
212
213class Person {
214 @Flow('getName', kebabCase)
215 logName;
216
217 constructor(firstName, lastName) {
218 this.firstName = firstName;
219 this.lastName = lastName;
220 }
221
222 getName() {
223 return `${this.firstName} ${this.lastName}`;
224 }
225}
226
227const person = new Person('Joe', 'Smith');
228
229person.logName(); // joe-smith
230```
231
232### Instance Decorators
233
234Normally decorators are applied to the prototype method
235of the class you are working with, but with some of these
236decorators that is not the desired behavour. These
237decorators are applied at the instance level.
238
239- `Debounce`
240- `Throttle`
241- `Memoize`
242- `After`
243- `Before`
244- `Curry`
245- `CurryRight`
246- `Once`
247- `Flow`
248- `FlowRight`
249- `Rearg`
250- `Negate`
251- `Flip`
252- `Bind`
253- `Partial`
254- `PartialRight`
255
256### Mixin
257
258You can mixin methods into a class by using the `Mixin` decorator.
259
260#### Example
261
262```javascript
263import { Mixin } from 'lodash-decorators';
264
265const MyOtherApi = {
266 someCoolMethod() {
267 // Do something cool
268 }
269};
270
271@Mixin(MyOtherApi)
272class Person {}
273
274Person.prototype.someCoolMethod === MyOtherApi.someCoolMethod; // => true
275```
276
277### Attempt
278
279You can wrap a method in a lodash attempt method.
280
281#### Example
282
283```javascript
284import { Attempt } from 'lodash-decorators';
285
286class Person {
287 @Attempt()
288 throwAnError() {
289 throw new Error();
290 }
291
292 @Attempt()
293 doNotThrowAnError() {
294 return '0_o';
295 }
296}
297
298const person = new Person();
299
300let result = person.throwAnError();
301
302result instanceof Error; // => true
303
304result = person.doNotThrowAnError();
305
306result === '0_o'; // => true
307```
308
309### Bind
310
311Bind takes arguments based on lodash's bind and binds the `Function` to
312the current instance object.
313
314#### Example
315
316```javascript
317import { Bind } from 'lodash-decorators'
318
319class Person {
320 constructor(firstName, lastName) {
321 this.firstName = firstName;
322 this.lastName = lastName;
323 }
324
325 @Bind()
326 getName() {
327 return `${this.firstName} ${this.lastName}`;
328 }
329
330 // It can also function as a partial
331 @Bind('Joe')
332 getUpperCaseName(name) {
333 return name.toUpperCase();
334 }
335}
336
337const person = new Person('Joe', 'Smith');
338
339person.getName.call(null); // Joe Smith
340person.getUpperCaseName(); // JOE
341```
342
343You can also bind entire classes with `bindAll` or `bind`.
344
345#### Example
346
347```javascript
348import { BindAll } from 'lodash-decorators'
349
350@BindAll()
351class Person {
352 constructor(firstName, lastName) {
353 this.firstName = firstName;
354 this.lastName = lastName;
355 }
356
357 getName() {
358 return `${this.firstName} ${this.lastName}`;
359 }
360}
361
362const person = new Person('Joe', 'Smith');
363
364person.getName.call(null); // Joe Smith
365```
366
367### v4 Breaking Changes
368
369Version 4 is a rewrite of the library and has many breaking changes.
370
371#### Not all decorators can be applied to or forced on getters/setters.
372
373Only certain decorators make sense to be applied to getters/setters. Before you could specify the target of the decorator like `debounce.set(15)`. This behavior is
374removed and decorators that make sense to apply to getters/setters are configured to be applied to methods and either the getter or the setter. For example:
375
376```javascript
377class MyClass {
378 // This only gets applied to the setter as it doesn't make sense to apply it to the getter.
379 @Debounce(1000)
380 get value() {
381 return this._value;
382 }
383
384 set value(val) {
385 this._value = val;
386 }
387
388 @Debounce(15)
389 fn() {}
390}
391```
392
393This keeps the API cleaner and doesn't require the developer to know how the decorator applies to the descriptor. Some decorators have explicit version that apply to either getters of setters, such as `ThrottleGetter` and `ThrottleSetter`.
394
395#### No longer force instance decorator onto prototype
396
397There is no longer a `Proto` decorator attached to instance decorators. Most instance decorators now have a counterpart that applies to the prototype instead of the instance. `Debounce.Proto()` is now `DebounceAll()`.
398
399#### All decorators now take arguments
400
401All decorators now take arguments. So instead of `@Once` you would do `@Once()`. This keeps the API consistent and doesn't require the developer to remember which decorators take arguments.
402
403#### Removal of extensions and validation package
404
405All extensions like `enumerable` have been removed in favor of [core-decorators](https://github.com/jayphelps/core-decorators.js). There may be some slight over lap like `debounce` and `throttle`. Fair warning, instance decorators may not play nice with other implementations of instance decorators.
406
407We want to keep lodash decorators focused specifically on lodash specific functions.
408
409#### Prototype decorator order no longer throws an error
410
411If a prototype decorator comes after an instance decorator it will be ignored since there is no way to apply it in the chain.
412
413#### Other breaking changes
414
415- `Attempt` now takes an argument to line up with lodash API.
416- `Bind` used on a class no longer delegates to `BindAll`. Use `BindAll` instead.
417- `Curry`, `Partial`, `Flow`, `FlowRight` are now instance decorators.
418
419### v4 Improvements
420
421- Ships with TypeScript typings.
422- Predictable performance.
423- Improvements to Bind decorator.
424- Improved API for decorator factory.
425- More and better unit tests.
426- Better performance with instance decorators.
427- Single imports with `import { Debounce } from 'lodash-decorators/debounce'`;
428- Composition decorators can be used on properties. These will generate the composed function.