0
# Utility Methods
1
2
Utility functions for working with memoized functions, composition, and type checking in the moize ecosystem.
3
4
## Capabilities
5
6
### Type Checking
7
8
Check if a value is a memoized function created by moize.
9
10
```typescript { .api }
11
/**
12
* Type guard to check if a value is a memoized function
13
* @param value The value to test
14
* @returns True if the value is a memoized function, false otherwise
15
*/
16
isMoized(value: any): value is Moized;
17
```
18
19
**Usage Examples:**
20
21
```typescript
22
import moize from "moize";
23
24
const regularFunction = (x: number) => x * 2;
25
const memoizedFunction = moize(regularFunction);
26
27
// Type checking
28
console.log(moize.isMoized(regularFunction)); // false
29
console.log(moize.isMoized(memoizedFunction)); // true
30
console.log(moize.isMoized("not a function")); // false
31
console.log(moize.isMoized(null)); // false
32
33
// Use in conditional logic
34
function processFunction(fn: any) {
35
if (moize.isMoized(fn)) {
36
console.log('Working with memoized function');
37
console.log('Cache size:', Array.from(fn.keys()).length);
38
console.log('Original function name:', fn.originalFunction.name);
39
40
// Access memoized function methods
41
fn.clear();
42
console.log('Cache cleared');
43
} else if (typeof fn === 'function') {
44
console.log('Working with regular function');
45
console.log('Function name:', fn.name);
46
} else {
47
console.log('Not a function');
48
}
49
}
50
51
processFunction(regularFunction); // "Working with regular function"
52
processFunction(memoizedFunction); // "Working with memoized function"
53
54
// Type-safe utility function
55
function getMemoizedFunctionStats(fn: unknown): { calls: number; hits: number } | null {
56
if (moize.isMoized(fn)) {
57
return fn.getStats();
58
}
59
return null;
60
}
61
62
const stats = getMemoizedFunctionStats(memoizedFunction);
63
console.log(stats); // { calls: 0, hits: 0 }
64
```
65
66
### Function Composition
67
68
Compose multiple moizers to create complex memoization strategies.
69
70
```typescript { .api }
71
/**
72
* Compose multiple moizers into a single moizer
73
* @param moizers The moizers or moize instances to compose
74
* @returns A composed moizer that applies all configurations
75
*/
76
compose(...moizers: Array<Moize | Moizer>): Moizer;
77
```
78
79
**Usage Examples:**
80
81
```typescript
82
import moize from "moize";
83
84
// Define individual moization strategies
85
const withCaching = moize.maxSize(50);
86
const withTTL = moize.maxAge(30000); // 30 seconds
87
const withProfiling = moize.profile('composed-functions');
88
const withDeepEquality = moize.deep;
89
90
// Compose strategies
91
const composedMemoizer = moize.compose(
92
withCaching,
93
withTTL,
94
withProfiling,
95
withDeepEquality
96
);
97
98
const expensiveOperation = (data: { items: any[]; config: any }) => {
99
return data.items
100
.filter(item => item.active)
101
.map(item => ({ ...item, processed: true, timestamp: Date.now() }));
102
};
103
104
// Apply composed memoization
105
const memoizedOperation = composedMemoizer(expensiveOperation);
106
107
// The function now has all composed behaviors:
108
// - Max 50 cache entries
109
// - 30 second TTL
110
// - Profiled under 'composed-functions'
111
// - Uses deep equality for comparison
112
113
console.log(memoizedOperation.options);
114
// Contains all merged options from composed moizers
115
116
// Complex composition example
117
const apiMemoizer = moize.compose(
118
moize.promise, // Handle async functions
119
moize.serialize, // Serialize complex arguments
120
moize.maxAge(60000), // 1 minute TTL
121
moize.maxSize(100), // Up to 100 cached responses
122
moize.profile('api-calls') // Profile API performance
123
);
124
125
const fetchUserData = async (userId: string, includePreferences: boolean) => {
126
const response = await fetch(`/api/users/${userId}?prefs=${includePreferences}`);
127
return response.json();
128
};
129
130
const memoizedFetchUserData = apiMemoizer(fetchUserData);
131
132
// Database operation composition
133
const dbMemoizer = moize.compose(
134
moize.promise,
135
moize.deep, // Deep comparison for query objects
136
moize.maxAge(120000), // 2 minute TTL
137
moize.transformArgs((key) => { // Normalize query objects
138
return key.map(arg => {
139
if (arg && typeof arg === 'object' && 'query' in arg) {
140
// Sort query keys for consistent caching
141
const sortedQuery = Object.keys(arg.query)
142
.sort()
143
.reduce((result, key) => {
144
result[key] = arg.query[key];
145
return result;
146
}, {} as any);
147
return { ...arg, query: sortedQuery };
148
}
149
return arg;
150
});
151
}),
152
moize.profile('database')
153
);
154
155
const queryDatabase = async (query: { table: string; where: any; limit?: number }) => {
156
// Database query implementation
157
return { results: [], count: 0 };
158
};
159
160
const memoizedDbQuery = dbMemoizer(queryDatabase);
161
```
162
163
### Composition Order and Behavior
164
165
The order of composition matters for certain options, with later moizers taking precedence.
166
167
```typescript
168
import moize from "moize";
169
170
const func = (x: number) => x * x;
171
172
// Order matters for conflicting options
173
const composed1 = moize.compose(
174
moize.maxSize(10), // This will be overridden
175
moize.maxSize(20) // This takes precedence
176
);
177
178
const composed2 = moize.compose(
179
moize.maxSize(20), // This will be overridden
180
moize.maxSize(10) // This takes precedence
181
);
182
183
const memoized1 = composed1(func);
184
const memoized2 = composed2(func);
185
186
console.log(memoized1.options.maxSize); // 20
187
console.log(memoized2.options.maxSize); // 10
188
189
// Non-conflicting options are merged
190
const mergedComposition = moize.compose(
191
moize.maxSize(15),
192
moize.maxAge(5000),
193
moize.deep,
194
moize.profile('merged')
195
);
196
197
const mergedMemoized = mergedComposition(func);
198
console.log(mergedMemoized.options);
199
// {
200
// maxSize: 15,
201
// maxAge: 5000,
202
// isDeepEqual: true,
203
// profileName: 'merged',
204
// // ... other options
205
// }
206
```
207
208
### Practical Composition Patterns
209
210
Common composition patterns for different use cases.
211
212
```typescript
213
import moize from "moize";
214
215
// API call memoization pattern
216
const createApiMemoizer = (cacheDuration: number, cacheSize: number, profileName: string) => {
217
return moize.compose(
218
moize.promise,
219
moize.serialize,
220
moize.maxAge(cacheDuration, {
221
updateExpire: true, // Refresh TTL on cache hits
222
onExpire: (key) => console.log(`API cache expired for:`, key)
223
}),
224
moize.maxSize(cacheSize),
225
moize.profile(profileName)
226
);
227
};
228
229
// Usage
230
const shortTermApiMemoizer = createApiMemoizer(30000, 50, 'short-api'); // 30s
231
const longTermApiMemoizer = createApiMemoizer(300000, 20, 'long-api'); // 5min
232
233
// Computation memoization pattern
234
const createComputationMemoizer = (isHeavyComputation: boolean) => {
235
const baseComposition = [
236
moize.deep, // Usually need deep equality for complex data
237
moize.profile('computations')
238
];
239
240
if (isHeavyComputation) {
241
return moize.compose(
242
...baseComposition,
243
moize.infinite, // No size limit for expensive computations
244
moize.transformArgs((key) => {
245
// Normalize computation arguments
246
return key.map(arg => {
247
if (Array.isArray(arg)) {
248
return [...arg].sort(); // Sort arrays for consistent caching
249
}
250
return arg;
251
});
252
})
253
);
254
} else {
255
return moize.compose(
256
...baseComposition,
257
moize.maxSize(100),
258
moize.maxAge(60000) // 1 minute for lighter computations
259
);
260
}
261
};
262
263
// React component memoization pattern
264
const createReactMemoizer = (useDeepComparison: boolean = false) => {
265
const composition = [moize.react, moize.maxSize(20)];
266
267
if (useDeepComparison) {
268
composition.push(moize.deep);
269
} else {
270
composition.push(moize.shallow);
271
}
272
273
return moize.compose(...composition);
274
};
275
276
// Development vs Production memoization
277
const createEnvironmentMemoizer = (isDevelopment: boolean) => {
278
const baseComposition = [
279
moize.maxSize(50),
280
moize.maxAge(60000)
281
];
282
283
if (isDevelopment) {
284
// More verbose profiling and smaller cache in development
285
return moize.compose(
286
...baseComposition,
287
moize.profile('dev-functions'),
288
moize.collectStats(true)
289
);
290
} else {
291
// Optimized for production
292
return moize.compose(
293
...baseComposition,
294
moize.serialize // Better cache key consistency in production
295
);
296
}
297
};
298
```