UNPKG

7.6 kBMarkdownView Raw
1# typescript-memoize
2
3[![npm](https://img.shields.io/npm/v/typescript-memoize.svg)](https://www.npmjs.com/package/typescript-memoize)
4[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/darrylhodgins/typescript-memoize/master/LICENSE)
5![Test](https://github.com/darrylhodgins/typescript-memoize/workflows/Test/badge.svg)
6
7A memoize decorator for Typescript.
8
9## Installation
10
11```
12npm install --save typescript-memoize
13```
14
15## Usage:
16
17```typescript
18@Memoize(hashFunction?: (...args: any[]) => any)
19```
20
21You can use it in four ways:
22
23* Memoize a `get` accessor,
24* Memoize a method which takes no parameters,
25* Memoize a method which varies based on its first parameter only,
26* Memoize a method which varies based on some combination of parameters
27
28You can call memoized methods *within* the same class, too. This could be useful if you want to memoize the return value for an entire data set, and also a filtered or mapped version of that same set.
29
30## Memoize a `get` accessor, or a method which takes no parameters
31
32These both work the same way. Subsequent calls to a memoized method without parameters, or to a `get` accessor, always return the same value.
33
34I generally consider it an anti-pattern for a call to a `get` accessor to trigger an expensive operation. Simply adding `Memoize()` to a `get` allows for seamless lazy-loading.
35
36```typescript
37import {Memoize,MemoizeExpiring} from 'typescript-memoize';
38
39class SimpleFoo {
40
41 // Memoize a method without parameters
42 @Memoize()
43 public getAllTheData() {
44 // do some expensive operation to get data
45 return data;
46 }
47
48 // Memoize a method and expire the value after some time in milliseconds
49 @MemoizeExpiring(5000)
50 public getDataForSomeTime() {
51 // do some expensive operation to get data
52 return data;
53 }
54
55 // Memoize a getter
56 @Memoize()
57 public get someValue() {
58 // do some expensive operation to calculate value
59 return value;
60 }
61
62}
63```
64
65And then we call them from somewhere else in our code:
66
67```typescript
68let simpleFoo = new SimpleFoo();
69
70// Memoizes a calculated value and returns it:
71let methodVal1 = simpleFoo.getAllTheData();
72
73// Returns memoized value
74let methodVal2 = simpleFoo.getAllTheData();
75
76// Memoizes (lazy-loads) a calculated value and returns it:
77let getterVal1 = simpleFoo.someValue;
78
79// Returns memoized value
80let getterVal2 = simpleFoo.someValue;
81
82```
83
84## Memoize a method which varies based on its first parameter only
85
86Subsequent calls to this style of memoized method will always return the same value.
87
88I'm not really sure why anyone would use this approach to memoize a method with *more* than one parameter, but it's possible.
89
90```typescript
91import {Memoize} from 'typescript-memoize';
92
93class ComplicatedFoo {
94
95 // Memoize a method without parameters (just like the first example)
96 @Memoize()
97 public getAllTheData() {
98 // do some expensive operation to get data
99 return data;
100 }
101
102 // Memoize a method with one parameter
103 @Memoize()
104 public getSomeOfTheData(id: number) {
105 let allTheData = this.getAllTheData(); // if you want to!
106 // do some expensive operation to get data
107 return data;
108 }
109
110 // Memoize a method with multiple parameters
111 // Only the first parameter will be used for memoization
112 @Memoize()
113 public getGreeting(name: string, planet: string) {
114 return 'Hello, ' + name + '! Welcome to ' + planet;
115 }
116
117}
118```
119
120We call these methods from somewhere else in our code:
121
122```typescript
123let complicatedFoo = new ComplicatedFoo();
124
125// Returns calculated value and memoizes it:
126let oneParam1 = complicatedFoo.getSomeOfTheData();
127
128// Returns memoized value
129let oneParam2 = complicatedFoo.getSomeOfTheData();
130
131// Memoizes a calculated value and returns it:
132// 'Hello, Darryl! Welcome to Earth'
133let greeterVal1 = complicatedFoo.getGreeting('Darryl', 'Earth');
134
135// Ignores the second parameter, and returns memoized value
136// 'Hello, Darryl! Welcome to Earth'
137let greeterVal2 = complicatedFoo.getGreeting('Darryl', 'Mars');
138```
139
140## Memoize a method which varies based on some combination of parameters
141
142Pass in a `hashFunction` which takes the same parameters as your target method, to memoize values based on all parameters, or some other custom logic
143
144```typescript
145import {Memoize} from 'typescript-memoize';
146
147class MoreComplicatedFoo {
148
149 // Memoize a method with multiple parameters
150 // Memoize will remember values based on keys like: 'name;planet'
151 @Memoize((name: string, planet: string) => {
152 return name + ';' + planet;
153 })
154 public getBetterGreeting(name: string, planet: string) {
155 return 'Hello, ' + name + '! Welcome to ' + planet;
156 }
157
158 // Memoize based on some other logic
159 @Memoize(() => {
160 return new Date();
161 })
162 public memoryLeak(greeting: string) {
163 return greeting + '!!!!!';
164 }
165
166 // Memoize also accepts parameters via a single object argument
167 @Memoize({
168 expiring: 10000, // milliseconds
169 hashFunction: (name: string, planet: string) => {
170 return name + ';' + planet;
171 }
172 })
173 public getSameBetterGreeting(name: string, planet: string) {
174 return 'Hello, ' + name + '! Welcome to ' + planet;
175 }
176
177}
178```
179
180We call these methods from somewhere else in our code. By now you should be getting the idea:
181
182```typescript
183let moreComplicatedFoo = new MoreComplicatedFoo();
184
185// 'Hello, Darryl! Welcome to Earth'
186let greeterVal1 = moreComplicatedFoo.getBetterGreeting('Darryl', 'Earth');
187
188// 'Hello, Darryl! Welcome to Mars'
189let greeterVal2 = moreComplicatedFoo.getBetterGreeting('Darryl', 'Mars');
190
191// Fill up the computer with useless greetings:
192let greeting = moreComplicatedFoo.memoryLeak('Hello');
193
194```
195
196## Memoize accepts one or more "tag" strings that allow the cache to be invalidated on command
197
198Passing an array with one or more "tag" strings these will allow you to later clear the cache of results associated with methods or the `get`accessors using the `clear()` function.
199
200The `clear()` function also requires an array of "tag" strings.
201
202```typescript
203import {Memoize} from 'typescript-memoize';
204
205class ClearableFoo {
206
207 // Memoize accepts tags
208 @Memoize({ tags: ["foo", "bar"] })
209 public getClearableGreeting(name: string, planet: string) {
210 return 'Hello, ' + name + '! Welcome to ' + planet;
211 }
212
213
214 // Memoize accepts tags
215 @Memoize({ tags: ["bar"] })
216 public getClearableSum(a: number, b: number) {
217 return a + b;
218 }
219
220}
221```
222
223We call these methods from somewhere else in our code.
224
225```typescript
226import {clear} from 'typescript-memoize';
227
228let clearableFoo = new ClearableFoo();
229
230// 'Hello, Darryl! Welcome to Earth'
231let greeterVal1 = clearableFoo.getClearableGreeting('Darryl', 'Earth');
232
233// Ignores the second parameter, and returns memoized value
234// 'Hello, Darryl! Welcome to Earth'
235let greeterVal2 = clearableFoo.getClearableGreeting('Darryl', 'Mars');
236
237// '3'
238let sum1 = clearableFoo.getClearableSum(2, 1);
239
240// Ignores the second parameter, and returns memoized value
241// '3'
242let sum2 = clearableFoo.getClearableSum(2, 2);
243
244clear(["foo"]);
245
246// The memoized values are cleared, return a new value
247// 'Hello, Darryl! Welcome to Mars'
248let greeterVal3 = clearableFoo.getClearableGreeting('Darryl', 'Mars');
249
250
251// The memoized value is not associated with 'foo' tag, returns memoized value
252// '3'
253let sum3 = clearableFoo.getClearableSum(2, 2);
254
255clear(["bar"]);
256
257// The memoized values are cleared, return a new value
258// 'Hello, Darryl! Welcome to Earth'
259let greeterVal4 = clearableFoo.getClearableGreeting('Darryl', 'Earth');
260
261
262// The memoized values are cleared, return a new value
263// '4'
264let sum4 = clearableFoo.getClearableSum(2, 2);
265
266```